name: [linux-clang]
include:
- name: linux-clang
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: clang
steps:
- name: Clone repository
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update -qq
- sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev clang-tools clang-format jq valgrind
+ sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python3 ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev clang-tools clang-format jq valgrind
# Temporary workaround for:
# https://github.com/actions/virtual-environments/issues/3185
sudo hostname localhost
name: [linux-clang]
include:
- name: linux-clang
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: clang
cflags: ''
steps:
sudo apt-get install -y bison comerr-dev flex doxygen
sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl
sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl
- sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python
+ sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3
sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils
sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind
- name: Install MIT Kerberos dependencies
name: [linux-clang, linux-gcc]
include:
- name: linux-clang
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: clang
cflags: ''
- name: linux-gcc
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: gcc
cflags: '-Wnonnull'
steps:
sudo apt-get install -y bison comerr-dev flex doxygen
sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl
sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl
- sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python
+ sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3
sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils
sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind
# Temporary workaround for:
- name: Install packages
run: |
echo "bison, flex, ncurses, texinfo, and unzip are in the base OS."
- echo "berkeley-db, perl, python, curl, and jq are installed in the"
+ echo "berkeley-db, perl, python3, curl, and jq are installed in the"
echo "base image already."
brew install autoconf automake libtool cpanm texinfo texi2html
sudo cpanm install JSON
name: [linux-clang]
include:
- name: linux-clang
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: clang
steps:
- name: Clone repository
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update -qq
- sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev clang-tools clang-format jq valgrind
+ sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python3 ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev clang-tools clang-format jq valgrind
# Temporary workaround for:
# https://github.com/actions/virtual-environments/issues/3185
sudo hostname localhost
name: [linux-clang, linux-gcc]
include:
- name: linux-clang
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: clang
cflags: '-fsanitize=undefined'
ldflags: ''
- name: linux-gcc
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: gcc
cflags: '-Wnonnull -fsanitize=undefined'
ldflags: ''
sudo apt-get install -y bison comerr-dev flex doxygen
sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl
sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl
- sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python
+ sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3
sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils
sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind
# Temporary workaround for:
name: [linux-clang]
include:
- name: linux-clang
- os: ubuntu-18.04
+ os: ubuntu-22.04
compiler: clang
steps:
- name: Clone repository
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update -qq
- sudo apt-get install -y bison comerr-dev flex libcap-ng-dev lmdb-utils liblmdb-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev jq valgrind
+ sudo apt-get install -y bison comerr-dev flex libcap-ng-dev lmdb-utils liblmdb-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python3 ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev jq valgrind
# Temporary workaround for:
# https://github.com/actions/virtual-environments/issues/3185
sudo hostname localhost
.Nm prune
command that can do this on the KDC side.
.El
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev KRB5_KTNAME
+Specifies the default keytab.
+.It Ev KRB5_CONFIG
+The file name of
+.Pa krb5.conf ,
+the default being
+.Pa /etc/krb5.conf .
+.El
+.Sh KEYTAB NAMING
+The syntax for the value of the
+.Ql KRB5_KTNAME
+environment variable and
+.Oo Fl k Ar keytab \*(Ba Xo
+.Fl Fl keytab= Ns Ar keytab
+.Xc
+.Oc
+options is
+.Ql TYPE:name
+where the TYPE is one of
+.Ql FILE ,
+.Ql HDBGET ,
+.Ql HDB ,
+or
+.Ql ANY ,
+and the name syntax is specific to the keytab type.
+.Pp
+For the FILE keytab type the name is the path to a file whose
+format is the well-known keytab file format used by MIT Kerberos,
+Heimdal, Java, and others.
+.Pp
+For the HDB and HDBGET keytab types the name syntax is
+.Ql [<path>][:mkey=<path>]
+where the first path is the path to the HDB and the second path
+is the path to the master key file.
+Note that to use the HDB and HDBGET keytab types in a program
+linked with Heimdal libraries one first load the
+.Ql libhdb
+library and then register their keytab methods using
+.Xr krb5_kt_register 3 .
+Note also that
+.Nm ktutil
+does not load and register the HDB and HDBGET keytab types at
+this time.
+.Pp
+The ANY keytab type name syntax is a sequence of other keytab
+names (including their TYPE: prefix) separated by commas.
+Note that there is no escape sequence for commas in keytab names.
.Sh SEE ALSO
.Xr kadmin 1
+.Xr kinit 1
+.Xr krb5_kt_register 3
LDFLAGS="${LIB_openssl_crypto} ${LDFLAGS}"
AC_CHECK_LIB([crypto], [OPENSSL_init],
[LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto"; openssl=yes], [openssl=no], [])
+ if test "$openssl" = "yes"; then
+ AC_CHECK_LIB([crypto],
+ [OSSL_EC_curve_nid2name],
+ [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_30], 1,
+ [whether OpenSSL is 3.0 or higher])]
+ )
+ AC_CHECK_HEADERS([openssl/fips.h],
+ [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_FIPS_H], 1,
+ [whether openssl/fips.h is available])]
+ )
+ AC_CHECK_LIB([crypto],
+ [FIPS_mode_set],
+ [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_FIPS_MODE_SET_API], 1,
+ [whether FIPS_mode_set API is available])]
+ )
+ fi
# These cases are just for static linking on older OSes,
# presumably.
if test "$openssl" = "no"; then
LDFLAGS="${saved_LDFLAGS}"
fi
-if test "$openssl" = "yes"; then
- AC_CHECK_LIB([crypto],
- [OSSL_EC_curve_nid2name],
- [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_30], 1,
- [whether OpenSSL is 3.0 or higher])]
- )
- AC_CHECK_HEADERS([openssl/fips.h],
- [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_FIPS_H], 1,
- [whether openssl/fips.h is available])]
- )
- AC_CHECK_LIB([crypto],
- [FIPS_mode_set],
- [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_FIPS_MODE_SET_API], 1,
- [whether FIPS_mode_set API is available])]
- )
-fi
-
LIB_hcrypto='$(top_builddir)/lib/hcrypto/libhcrypto.la'
LIB_hcrypto_a='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.a'
LIB_hcrypto_so='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.so'
env KRB5_CONFIG=$HOME/etc/krb5.conf kinit user@@REALM
@end example
+@cindex KRB5CCNAME
+The Heimdal libraries and commands (and the MIT ones too), support the
+use of the environment variable @samp{KRB5CCNAME} for specifying a
+credentials cache to use. See the @manpage{kinit,1} for details.
+
+@cindex KRB5_KTNAME
+The Heimdal libraries and commands (and the MIT ones too), support the
+use of the environment variable @samp{KRB5_KTNAME} for specifying a
+keytab file to use for server operations. See the @manpage{kinit,1} for
+details.
+
+@cindex KRB5_CLIENT_KTNAME
+The Heimdal libraries and commands (and the MIT ones too), support the
+use of the environment variable @samp{KRB5_CLIENT_KTNAME} for specifying
+a keytab file to use for client operations. See the @manpage{kinit,1}
+for details.
+
@cindex GSS_MECH_CONFIG
The GSS-API mechanism configuration file can also be changed from the
default with the enviornment variable @samp{GSS_MECH_CONFIG}. Note that
long = "krb5-config-file"
short = "C"
type = "string"
- help = "filename to save the principal's krb5.confg in"
+ help = "filename to save the principal's krb5.conf in"
}
option = {
long = "upto"
.Op Fl Fl expiration-time= Ns Ar time
.Op Fl Fl pw-expiration-time= Ns Ar time
.Op Fl Fl policy= Ns Ar policy-name
+.Op Fl Fl use-defaults
.Ar principal...
.Bd -ragged -offset indent
Adds a new principal to the database. The options not passed on the
The only policy supported by Heimdal servers is
.Ql default .
.Pp
+If some parameters are not given then they will be prompted for
+unless the
+.Fl Fl use-defaults
+option is given, in which case defaults will be taken from the
+principal named
+.Dq default .
+.Pp
This command has the following aliases:
.Nm ank ,
.Nm add_new_key .
.Ed
.Pp
.Nm prune
-.Ar principal [kvno]
+.Oo Fl Fl kvno= Ns Ar number
+.Oc
+.Ar principal
.Bd -ragged -offset indent
Deletes the named principal's keys of the given kvno. If a kvno is
-not given then this deletes all the named principals keys that are
+not given then this deletes all the named principal's keys that are
too old to be needed for decrypting tickets issued using those keys
(i.e., any such tickets are necessarily expired). The determination
of "too old" is made using the max-ticket-life attribute of the
.Pp
.Nm ext_keytab
.Oo Fl k Ar keytab \*(Ba Xo
+.Op Fl Fl random-key
.Op Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall
.Op Fl Fl enctypes= Ns Ar string
.Fl Fl keytab= Ns Ar string
Creates a keytab with the keys of the specified principals. Requires
get-keys rights, otherwise the principal's keys are changed and saved in
the keytab.
+.Pp
+If the
+.Fl Fl random-key
+option is given then new randomly-generated keys will be set on
+the principal.
+.Pp
If enctypes to use are not given, then the
.Ar [libdefaults] supported_enctypes
configuration parameter will be used on the client side to select
.Op Fl t | Fl Fl terse
.Op Fl o Ar string | Fl Fl column-info= Ns Ar string
.Op Fl C Ar path | Fl Fl krb5-config-file= Ns Ar path
+.Op Fl Fl upto= Ns Ar number
.Ar principal...
.Bd -ragged -offset indent
Lists the matching principals, short prints the result as a table,
-while long format produces a more verbose output. Which columns to
-print can be selected with the
+while long format produces a more verbose output.
+If the
+.Fl Fl upto= Ns Ar number
+option is given, then only up to that many principals will be
+listed.
+.Pp
+Which columns to print can be selected with the
.Fl o
option. The argument is a comma separated list of column names
optionally appended with an equal sign
.Op Fl Fl kvno= Ns Ar number
.Op Fl Fl policy= Ns Ar policy-name
.Op Fl Fl alias= Ns Ar alias-name
+.Op Fl Fl constrained-delegation= Ns Ar principal-name
+.Op Fl Fl pkinit-acl= Ns Ar subject-name
+.Op Fl Fl service-enctypes= Ns Ar enctype
.Op Fl C Ar path | Fl Fl krb5-config-file= Ns Ar path
.Ar principal...
.Bd -ragged -offset indent
.Pp
kadmin -l modify -a -disallow-proxiable user
.Pp
+The
+.Fl Fl constrained-delegation= Ns Ar principal-name
+option is not currently implemented.
+.Pp
+The
+.Fl Fl pkinit-acl= Ns Ar subject-name
+option authorizes clients with certificates with the given
+subject distinguished name to get tickets for the principal using
+PKINIT.
+This option can be given multiple times.
+The PKINIT ACLs set with this option will replace the existing
+ones.
+.Pp
+The
+.Fl Fl service-enctypes= Ns Ar enctype
+option indicates that the service supports the given enctype
+regardless of whether the service has long-term keys of that
+enctype.
+This option can be given multiple times and will replace the
+existing set of enctypes supported by the service.
+If a service principal does not have any supported enctypes then
+the KDC will assume that it supports only the enctypes of all of
+its long-term keys.
+.Pp
This command has the following alias:
.Nm mod .
.Ed
.Nm init
.Op Fl Fl realm-max-ticket-life= Ns Ar string
.Op Fl Fl realm-max-renewable-life= Ns Ar string
+.Op Fl Fl bare
.Ar realm
.Bd -ragged -offset indent
-Initializes the Kerberos database with entries for a new realm. It's
-possible to have more than one realm served by one server.
+Initializes the Kerberos database with entries for a new realm.
+It's possible to have more than one realm served by one server
+with the same database.
+.Pp
+If the
+.Fl Fl bare
+option is given, then only the root krbtgt principal for that
+realm will be created.
.Ed
.Pp
.Nm load
.Oc
.Op Fl Fl convert-file
.Op Fl Fl master-key-fd= Ns Ar fd
+.Op Fl Fl random-password
.Bd -ragged -offset indent
Writes the Kerberos master key to a file used by the KDC.
.Pp
+If the
+.Fl Fl convert-file
+option is given then convert an existing file to the new format.
+If the
+.Fl Fl master-key-fd= Ns Ar fd
+option is given the the password will be read from the given file
+descriptor.
+If the
+.Fl Fl random-password
+option is given then a password will be generated randomly.
+.Pp
This command has the following alias:
.Nm kstash .
.Ed
s[k++] = c;
break;
default:
- if (isalnum(c)) {
+ if (isalnum((unsigned char)c)) {
s[k++] = c;
} else {
s[k++] = '%';
case '/':
continue;
default:
- if (isalnum(c))
+ if (isalnum((unsigned char)c))
continue;
sz += 2;
}
#define KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED 7 /* couldn't map GSS/PKINIT name to principal */
#define KDC_AUTH_EVENT_PREAUTH_FAILED 8 /* generic PA failure */
#define KDC_AUTH_EVENT_PREAUTH_SUCCEEDED 9 /* generic (non-long term key) PA success */
+#define KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY 10 /* PA failed to validate current long term key, but historic */
/*
* Audit keys to be queried using kdc_audit_getkv(). There are other keys
#define KDC_REQUEST_KV_AUTH_EVENT "#auth_event" /* heim_number_t */
#define KDC_REQUEST_KV_PA_NAME "pa" /* heim_string_t */
#define KDC_REQUEST_KV_PA_ETYPE "pa-etype" /* heim_number_t */
+#define KDC_REQUEST_KV_PA_SUCCEEDED_KVNO "pa-succeeded-kvno" /* heim_number_t */
+#define KDC_REQUEST_KV_PA_FAILED_KVNO "pa-failed-kvno" /* heim_number_t */
#define KDC_REQUEST_KV_GSS_INITIATOR "gss_initiator" /* heim_string_t */
#define KDC_REQUEST_KV_PKINIT_CLIENT_CERT "pkinit_client_cert" /* heim_string_t */
+#define KDC_REQUEST_KV_PA_HISTORIC_KVNO "pa-historic-kvno" /* heim_number_t */
#endif /* HEIMDAL_KDC_KDC_AUDIT_H */
unsigned int rk_is_subkey : 1;
unsigned int fast_asserted : 1;
unsigned int explicit_armor_present : 1;
+ krb5_keyblock enc_ad_key;
krb5_crypto armor_crypto;
hdb_entry *armor_server;
}
static krb5_error_code
-pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
+pa_enc_chal_decrypt_kvno(astgs_request_t r,
+ krb5_enctype aenctype,
+ krb5_data *pepper1client,
+ krb5_data *pepper1kdc,
+ krb5_data *pepper2,
+ krb5_kvno kvno,
+ EncryptedData *enc_data,
+ krb5_keyblock *KDCchallengekey,
+ struct Key **used_key)
{
- krb5_data pepper1, pepper2;
- int invalidPassword = 0;
- EncryptedData enc_data;
- krb5_enctype aenctype;
+ unsigned int invalidKeys = 0;
krb5_error_code ret;
- struct Key *k;
- size_t size;
- int i;
+ const Keys *keys = NULL;
+ unsigned int i;
- heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST");
-
- if (_kdc_is_anon_request(&r->req)) {
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- kdc_log(r->context, r->config, 4, "ENC-CHALL doesn't support anon");
- return ret;
- }
-
- if (r->client->flags.locked_out) {
- ret = KRB5KDC_ERR_CLIENT_REVOKED;
- kdc_log(r->context, r->config, 0,
- "Client (%s) is locked out", r->cname);
- kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
- KDC_AUTH_EVENT_CLIENT_LOCKED_OUT);
- return ret;
- }
+ if (KDCchallengekey)
+ krb5_keyblock_zero(KDCchallengekey);
+ if (used_key)
+ *used_key = NULL;
- ret = decode_EncryptedData(pa->padata_value.data,
- pa->padata_value.length,
- &enc_data,
- &size);
- if (ret) {
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s",
- r->cname);
- return ret;
+ keys = hdb_kvno2keys(r->context, r->client, kvno);
+ if (keys == NULL) {
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
}
- pepper1.data = "clientchallengearmor";
- pepper1.length = strlen(pepper1.data);
- pepper2.data = "challengelongterm";
- pepper2.length = strlen(pepper2.data);
-
- krb5_crypto_getenctype(r->context, r->armor_crypto, &aenctype);
-
- kdc_log(r->context, r->config, 5, "FAST armor enctype is: %d", (int)aenctype);
-
- for (i = 0; i < r->client->keys.len; i++) {
+ for (i = 0; i < keys->len; i++) {
+ struct Key *k = &keys->val[i];
krb5_crypto challengecrypto, longtermcrypto;
- krb5_keyblock challengekey;
+ krb5_keyblock client_challengekey;
- k = &r->client->keys.val[i];
-
ret = krb5_crypto_init(r->context, &k->key, 0, &longtermcrypto);
if (ret)
continue;
-
+
ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto,
- &pepper1, &pepper2, aenctype,
- &challengekey);
+ pepper1client, pepper2, aenctype,
+ &client_challengekey);
if (ret) {
krb5_crypto_destroy(r->context, longtermcrypto);
continue;
}
-
- ret = krb5_crypto_init(r->context, &challengekey, 0,
+
+ ret = krb5_crypto_init(r->context, &client_challengekey, 0,
&challengecrypto);
- krb5_free_keyblock_contents(r->context, &challengekey);
+ krb5_free_keyblock_contents(r->context, &client_challengekey);
if (ret) {
krb5_crypto_destroy(r->context, longtermcrypto);
continue;
ret = _krb5_validate_pa_enc_challenge(r->context,
challengecrypto,
KRB5_KU_ENC_CHALLENGE_CLIENT,
- &enc_data,
+ enc_data,
r->cname);
krb5_crypto_destroy(r->context, challengecrypto);
if (ret) {
krb5_crypto_destroy(r->context, longtermcrypto);
- invalidPassword = (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY);
- if (!invalidPassword) {
- goto out;
- }
+ if (ret != KRB5KRB_AP_ERR_BAD_INTEGRITY)
+ return ret;
+
+ invalidKeys += 1;
+
+ if (pepper1kdc == NULL)
+ /* The caller is not interessted in details */
+ continue;
ret2 = krb5_enctype_to_string(r->context, k->key.keytype, &str);
if (ret2)
continue;
}
-
- /*
- * Found a key that the client used, lets pick that as the reply key
- */
- krb5_free_keyblock_contents(r->context, &r->reply_key);
- ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key);
- if (ret) {
- krb5_crypto_destroy(r->context, longtermcrypto);
- goto out;
+ if (pepper1kdc == NULL) {
+ /* The caller is not interessted in details */
+ return 0;
}
- krb5_free_keyblock_contents(r->context, &challengekey);
+ heim_assert(KDCchallengekey != NULL,
+ "KDCchallengekey pointer required with pepper1kdc");
+ heim_assert(used_key != NULL,
+ "used_key pointer required with pepper1kdc");
/*
* Provide KDC authentication to the client, uses a different
* challenge key (different pepper).
*/
- pepper1.data = "kdcchallengearmor";
- pepper1.length = strlen(pepper1.data);
-
ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto,
- &pepper1, &pepper2, aenctype,
- &challengekey);
+ pepper1kdc, pepper2, aenctype,
+ KDCchallengekey);
krb5_crypto_destroy(r->context, longtermcrypto);
if (ret)
- goto out;
+ return ret;
+
+ *used_key = k;
+ return 0;
+ }
+
+ if (invalidKeys == 0)
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+}
+
+static krb5_error_code
+pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
+{
+ krb5_kvno kvno = r->client->kvno;
+ krb5_data pepper1client, pepper1kdc, pepper2;
+ EncryptedData enc_data;
+ krb5_enctype aenctype;
+ krb5_error_code ret;
+ krb5_keyblock KDCchallengekey;
+ struct Key *k = NULL;
+ size_t size;
+
+ heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST");
+
+ if (_kdc_is_anon_request(&r->req)) {
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ kdc_log(r->context, r->config, 4, "ENC-CHAL doesn't support anon");
+ return ret;
+ }
+
+ if (r->client->flags.locked_out) {
+ ret = KRB5KDC_ERR_CLIENT_REVOKED;
+ kdc_log(r->context, r->config, 0,
+ "Client (%s) is locked out", r->cname);
+ kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
+ KDC_AUTH_EVENT_CLIENT_LOCKED_OUT);
+ return ret;
+ }
+
+ ret = decode_EncryptedData(pa->padata_value.data,
+ pa->padata_value.length,
+ &enc_data,
+ &size);
+ if (ret) {
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s",
+ r->cname);
+ return ret;
+ }
+
+ pepper1client.data = "clientchallengearmor";
+ pepper1client.length = strlen(pepper1client.data);
+ pepper1kdc.data = "kdcchallengearmor";
+ pepper1kdc.length = strlen(pepper1kdc.data);
+ pepper2.data = "challengelongterm";
+ pepper2.length = strlen(pepper2.data);
+
+ krb5_crypto_getenctype(r->context, r->armor_crypto, &aenctype);
+
+ kdc_log(r->context, r->config, 5, "FAST armor enctype is: %d", (int)aenctype);
+
+ ret = pa_enc_chal_decrypt_kvno(r, aenctype,
+ &pepper1client,
+ &pepper1kdc,
+ &pepper2,
+ kvno,
+ &enc_data,
+ &KDCchallengekey,
+ &k);
+ if (ret == KRB5KDC_ERR_ETYPE_NOSUPP) {
+ char *estr;
+ _kdc_set_e_text(r, "No key matching entype");
+ if(krb5_enctype_to_string(r->context, enc_data.etype, &estr))
+ estr = NULL;
+ if(estr == NULL)
+ _kdc_r_log(r, 4,
+ "No client key matching ENC-CHAL (%d) -- %s",
+ enc_data.etype, r->cname);
+ else
+ _kdc_r_log(r, 4,
+ "No client key matching ENC-CHAL (%s) -- %s",
+ estr, r->cname);
+ free(estr);
+ free_EncryptedData(&enc_data);
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_FAILED_KVNO,
+ kvno);
+ return ret;
+ }
+ if (ret == KRB5KRB_AP_ERR_SKEW) {
+ /*
+ * Logging happens inside of
+ * _krb5_validate_pa_enc_challenge()
+ * via pa_enc_chal_decrypt_kvno()
+ */
+
+ free_EncryptedData(&enc_data);
+ kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
+ KDC_AUTH_EVENT_CLIENT_TIME_SKEW);
+
+ /*
+ * The following is needed to make windows clients to
+ * retry using the timestamp in the error message, if
+ * there is a e_text, they become unhappy.
+ */
+ r->e_text = NULL;
+ return ret;
+ }
+ if (ret == KRB5KDC_ERR_PREAUTH_FAILED) {
+ krb5_error_code hret = ret;
+ int hi;
+
+ /*
+ * Logging happens inside of
+ * via pa_enc_chal_decrypt_kvno()
+ */
+
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_FAILED_KVNO,
+ kvno);
+
+ /*
+ * Check if old and older keys are
+ * able to decrypt.
+ */
+ for (hi = 1; hi < 3; hi++) {
+ krb5_kvno hkvno;
+
+ if (hi >= kvno) {
+ break;
+ }
+
+ hkvno = kvno - hi;
+ hret = pa_enc_chal_decrypt_kvno(r, aenctype,
+ &pepper1client,
+ NULL, /* pepper1kdc */
+ &pepper2,
+ hkvno,
+ &enc_data,
+ NULL, /* KDCchallengekey */
+ NULL); /* used_key */
+ if (hret == 0) {
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_HISTORIC_KVNO,
+ hkvno);
+ break;
+ }
+ if (hret == KRB5KDC_ERR_ETYPE_NOSUPP) {
+ break;
+ }
+ }
- ret = krb5_crypto_init(r->context, &challengekey, 0, &challengecrypto);
- krb5_free_keyblock_contents(r->context, &challengekey);
+ free_EncryptedData(&enc_data);
+
+ if (hret == 0)
+ kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
+ KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY);
+ else
+ kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
+ KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY);
+
+ return ret;
+ }
+ free_EncryptedData(&enc_data);
+ if (ret == 0) {
+ krb5_crypto challengecrypto;
+ char *estr = NULL;
+ char *astr = NULL;
+ char *kstr = NULL;
+
+ ret = krb5_crypto_init(r->context, &KDCchallengekey, 0, &challengecrypto);
+ krb5_free_keyblock_contents(r->context, &KDCchallengekey);
if (ret)
- goto out;
+ return ret;
ret = _krb5_make_pa_enc_challenge(r->context, challengecrypto,
KRB5_KU_ENC_CHALLENGE_KDC,
r->rep.padata);
krb5_crypto_destroy(r->context, challengecrypto);
if (ret)
- goto out;
-
- if (ret == 0)
- ret = set_salt_padata(r->context, r->config,
- r->rep.padata, k);
+ return ret;
+
+ ret = set_salt_padata(r->context, r->config, r->rep.padata, k);
+ if (ret)
+ return ret;
/*
- * Success
+ * Found a key that the client used, lets pick that as the reply key
*/
+
+ krb5_free_keyblock_contents(r->context, &r->reply_key);
+ ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key);
+ if (ret)
+ return ret;
+
+ if (krb5_enctype_to_string(r->context, (int)aenctype, &astr))
+ astr = NULL;
+ if (krb5_enctype_to_string(r->context, enc_data.etype, &estr))
+ estr = NULL;
+ if (krb5_enctype_to_string(r->context, k->key.keytype, &kstr))
+ kstr = NULL;
+ _kdc_r_log(r, 4, "ENC-CHAL Pre-authentication succeeded -- %s "
+ "using armor=%s enc=%s key=%s",
+ r->cname,
+ astr ? astr : "unknown enctype",
+ estr ? estr : "unknown enctype",
+ kstr ? kstr : "unknown enctype");
kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY);
- goto out;
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_SUCCEEDED_KVNO,
+ kvno);
+ return 0;
}
- if (invalidPassword) {
- kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
- KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY);
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
- } else {
- ret = KRB5KDC_ERR_ETYPE_NOSUPP;
+ return ret;
+}
+
+static krb5_error_code
+pa_enc_ts_decrypt_kvno(astgs_request_t r,
+ krb5_kvno kvno,
+ const EncryptedData *enc_data,
+ krb5_data *ts_data,
+ Key **_pa_key)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+ Key *pa_key = NULL;
+ const Keys *keys = NULL;
+
+ if (_pa_key)
+ *_pa_key = NULL;
+
+ krb5_data_zero(ts_data);
+
+ keys = hdb_kvno2keys(r->context, r->client, kvno);
+ if (keys == NULL) {
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+ }
+ ret = hdb_enctype2key(r->context, r->client, keys,
+ enc_data->etype, &pa_key);
+ if(ret){
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
}
- out:
- free_EncryptedData(&enc_data);
- return ret;
+ try_next_key:
+ ret = krb5_crypto_init(r->context, &pa_key->key, 0, &crypto);
+ if (ret) {
+ const char *msg = krb5_get_error_message(r->context, ret);
+ _kdc_r_log(r, 4, "krb5_crypto_init failed: %s", msg);
+ krb5_free_error_message(r->context, msg);
+ return ret;
+ }
+
+ ret = krb5_decrypt_EncryptedData(r->context,
+ crypto,
+ KRB5_KU_PA_ENC_TIMESTAMP,
+ enc_data,
+ ts_data);
+ krb5_crypto_destroy(r->context, crypto);
+ /*
+ * Since the user might have several keys with the same
+ * enctype but with diffrent salting, we need to try all
+ * the keys with the same enctype.
+ */
+ if (ret) {
+ ret = hdb_next_enctype2key(r->context, r->client, keys,
+ enc_data->etype, &pa_key);
+ if (ret == 0)
+ goto try_next_key;
+
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ if (_pa_key)
+ *_pa_key = pa_key;
+ return 0;
}
static krb5_error_code
pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa)
{
+ krb5_kvno kvno = r->client->kvno;
EncryptedData enc_data;
krb5_error_code ret;
- krb5_crypto crypto;
krb5_data ts_data;
PA_ENC_TS_ENC p;
size_t len;
goto out;
}
- ret = hdb_enctype2key(r->context, r->client, NULL,
- enc_data.etype, &pa_key);
- if(ret){
+ ret = pa_enc_ts_decrypt_kvno(r, kvno, &enc_data, &ts_data, &pa_key);
+ if (ret == KRB5KDC_ERR_ETYPE_NOSUPP) {
char *estr;
_kdc_set_e_text(r, "No key matching entype");
- ret = KRB5KDC_ERR_ETYPE_NOSUPP;
if(krb5_enctype_to_string(r->context, enc_data.etype, &estr))
estr = NULL;
if(estr == NULL)
estr, r->cname);
free(estr);
free_EncryptedData(&enc_data);
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_FAILED_KVNO,
+ kvno);
goto out;
}
-
- try_next_key:
- ret = krb5_crypto_init(r->context, &pa_key->key, 0, &crypto);
- if (ret) {
- const char *msg = krb5_get_error_message(r->context, ret);
- _kdc_r_log(r, 4, "krb5_crypto_init failed: %s", msg);
- krb5_free_error_message(r->context, msg);
- free_EncryptedData(&enc_data);
- goto out;
- }
-
- ret = krb5_decrypt_EncryptedData (r->context,
- crypto,
- KRB5_KU_PA_ENC_TIMESTAMP,
- &enc_data,
- &ts_data);
- krb5_crypto_destroy(r->context, crypto);
- /*
- * Since the user might have several keys with the same
- * enctype but with diffrent salting, we need to try all
- * the keys with the same enctype.
- */
- if(ret){
+ if (ret == KRB5KDC_ERR_PREAUTH_FAILED) {
krb5_error_code ret2;
const char *msg = krb5_get_error_message(r->context, ret);
+ krb5_error_code hret = ret;
+ int hi;
+
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_FAILED_KVNO,
+ kvno);
- ret2 = krb5_enctype_to_string(r->context,
- pa_key->key.keytype, &str);
+ /*
+ * Check if old and older keys are
+ * able to decrypt.
+ */
+ for (hi = 1; hi < 3; hi++) {
+ krb5_kvno hkvno;
+
+ if (hi >= kvno) {
+ break;
+ }
+
+ hkvno = kvno - hi;
+ hret = pa_enc_ts_decrypt_kvno(r, hkvno,
+ &enc_data,
+ &ts_data,
+ NULL); /* pa_key */
+ if (hret == 0) {
+ krb5_data_free(&ts_data);
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_HISTORIC_KVNO,
+ hkvno);
+ break;
+ }
+ if (hret == KRB5KDC_ERR_ETYPE_NOSUPP) {
+ break;
+ }
+ }
+
+ ret2 = krb5_enctype_to_string(r->context, enc_data.etype, &str);
if (ret2)
str = NULL;
_kdc_r_log(r, 2, "Failed to decrypt PA-DATA -- %s "
krb5_xfree(str);
krb5_free_error_message(r->context, msg);
kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_PA_ETYPE,
- pa_key->key.keytype);
- kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
- KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY);
- if(hdb_next_enctype2key(r->context, r->client, NULL,
- enc_data.etype, &pa_key) == 0)
- goto try_next_key;
+ enc_data.etype);
+ if (hret == 0)
+ kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
+ KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY);
+ else
+ kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
+ KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY);
free_EncryptedData(&enc_data);
}
free_PA_ENC_TS_ENC(&p);
- ret = set_salt_padata(r->context, r->config,
- r->rep.padata, pa_key);
+ ret = set_salt_padata(r->context, r->config, r->rep.padata, pa_key);
if (ret == 0)
ret = krb5_copy_keyblock_contents(r->context, &pa_key->key, &r->reply_key);
if (ret)
pa_key->key.keytype);
kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY);
+ kdc_audit_setkv_number((kdc_request_t)r,
+ KDC_REQUEST_KV_PA_SUCCEEDED_KVNO,
+ kvno);
ret = 0;
KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length);
if (ret)
return ret;
-
+
+ if (!r->config->enable_fast)
+ return 0;
+
return krb5_padata_add(r->context, r->ek.encrypted_pa_data,
KRB5_PADATA_FX_FAST, NULL, 0);
}
if (!r->armor_crypto && (pat[n].flags & PA_REQ_FAST))
continue;
+ if (pat[n].type == KRB5_PADATA_PKINIT_KX && !r->config->allow_anonymous)
+ continue;
if (pat[n].type == KRB5_PADATA_ENC_TIMESTAMP) {
if (r->armor_crypto && !r->config->enable_armored_pa_enc_timestamp)
continue;
if (!r->armor_crypto && !r->config->enable_unarmored_pa_enc_timestamp)
continue;
}
+ if (pat[n].type == KRB5_PADATA_FX_FAST && !r->config->enable_fast)
+ continue;
+ if (pat[n].type == KRB5_PADATA_GSS && !r->config->enable_gss_preauth)
+ continue;
ret = krb5_padata_add(r->context, r->rep.padata,
pat[n].type, NULL, 0);
if (r->armor_server)
_kdc_free_ent(r->context, r->armor_serverdb, r->armor_server);
krb5_free_keyblock_contents(r->context, &r->reply_key);
+ krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
krb5_free_keyblock_contents(r->context, &r->session_key);
krb5_free_keyblock_contents(r->context, &r->strengthen_key);
krb5_pac_free(r->context, r->pac);
rep->pvno = 5;
rep->msg_type = krb_tgs_rep;
- et->authtime = tgt->authtime;
+ if (et->authtime == 0)
+ et->authtime = tgt->authtime;
_kdc_fix_time(&b->till);
et->endtime = min(tgt->endtime, *b->till);
ALLOC(et->starttime);
const char *from,
const struct sockaddr *from_addr,
time_t **csec,
- int **cusec,
- AuthorizationData **auth_data)
+ int **cusec)
{
krb5_kdc_configuration *config = r->config;
KDC_REQ_BODY *b = &r->req.req_body;
krb5_auth_context ac = NULL;
krb5_flags ap_req_options;
krb5_flags verify_ap_req_flags = 0;
- krb5_crypto crypto;
krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
krb5uint32 krbtgt_kvno_try;
int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
Key *tkey;
krb5_keyblock *subkey = NULL;
- unsigned usage;
- *auth_data = NULL;
*csec = NULL;
*cusec = NULL;
goto out;
}
- usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
r->rk_is_subkey = 1;
ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
goto out;
}
if(subkey == NULL){
- usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
r->rk_is_subkey = 0;
ret = krb5_auth_con_getkey(r->context, ac, &subkey);
if (ret)
goto out;
+ krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
if (b->enc_authorization_data) {
- krb5_data ad;
-
- ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto);
- if (ret) {
- const char *msg = krb5_get_error_message(r->context, ret);
- krb5_auth_con_free(r->context, ac);
- kdc_log(r->context, config, 4, "krb5_crypto_init failed: %s", msg);
- krb5_free_error_message(r->context, msg);
- goto out;
- }
- ret = krb5_decrypt_EncryptedData (r->context,
- crypto,
- usage,
- b->enc_authorization_data,
- &ad);
- krb5_crypto_destroy(r->context, crypto);
- if(ret){
- krb5_auth_con_free(r->context, ac);
- kdc_log(r->context, config, 4,
- "Failed to decrypt enc-authorization-data");
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
- goto out;
- }
- ALLOC(*auth_data);
- if (*auth_data == NULL) {
- krb5_auth_con_free(r->context, ac);
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
- goto out;
- }
- ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
- if(ret){
- krb5_auth_con_free(r->context, ac);
- free(*auth_data);
- *auth_data = NULL;
- kdc_log(r->context, config, 4, "Failed to decode authorization data");
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+ ret = krb5_copy_keyblock_contents(r->context,
+ &r->reply_key,
+ &r->enc_ad_key);
+ if (ret)
goto out;
- }
}
ret = validate_fast_ad(r, r->ticket->ticket.authorization_data);
static krb5_error_code
tgs_build_reply(astgs_request_t priv,
krb5_enctype krbtgt_etype,
- AuthorizationData **auth_data,
const struct sockaddr *from_addr)
{
krb5_context context = priv->context;
krb5_principal_get_comp_string(context, priv->krbtgt->principal, 1);
char **capath = NULL;
size_t num_capath = 0;
+ AuthorizationData *auth_data = NULL;
HDB *krbtgt_outdb;
hdb_entry *krbtgt_out = NULL;
if (ret)
goto out;
+ if (b->enc_authorization_data) {
+ unsigned auth_data_usage;
+ krb5_crypto crypto;
+ krb5_data ad;
+
+ if (priv->rk_is_subkey != 0) {
+ auth_data_usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
+ } else {
+ auth_data_usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
+ }
+
+ ret = krb5_crypto_init(context, &priv->enc_ad_key, 0, &crypto);
+ if (ret) {
+ const char *msg = krb5_get_error_message(context, ret);
+ kdc_audit_addreason((kdc_request_t)priv,
+ "krb5_crypto_init() failed for "
+ "enc_authorization_data");
+ kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
+ krb5_free_error_message(context, msg);
+ goto out;
+ }
+ ret = krb5_decrypt_EncryptedData(context,
+ crypto,
+ auth_data_usage,
+ b->enc_authorization_data,
+ &ad);
+ krb5_crypto_destroy(context, crypto);
+ if(ret){
+ kdc_audit_addreason((kdc_request_t)priv,
+ "Failed to decrypt enc-authorization-data");
+ kdc_log(context, config, 4,
+ "Failed to decrypt enc-authorization-data");
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+ goto out;
+ }
+ ALLOC(auth_data);
+ if (auth_data == NULL) {
+ krb5_data_free(&ad);
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+ goto out;
+ }
+ ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
+ krb5_data_free(&ad);
+ if(ret){
+ free(auth_data);
+ auth_data = NULL;
+ kdc_audit_addreason((kdc_request_t)priv,
+ "Failed to decode authorization data");
+ kdc_log(context, config, 4, "Failed to decode authorization data");
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+ goto out;
+ }
+ }
+
/*
* Check flags
*/
&tkey_sign->key,
&sessionkey,
kvno,
- *auth_data,
+ auth_data,
tgt_realm,
rodc_id,
add_ticket_sig);
krb5_free_principal(context, krbtgt_out_principal);
free(ref_realm);
+ if (auth_data) {
+ free_AuthorizationData(auth_data);
+ free(auth_data);
+ }
+
free_EncTicketPart(&adtkt);
krb5_pac_free(context, user2user_pac);
const char *from = r->from;
struct sockaddr *from_addr = r->addr;
int datagram_reply = r->datagram_reply;
- AuthorizationData *auth_data = NULL;
krb5_error_code ret;
int i = 0;
const PA_DATA *tgs_req, *pa;
ret = tgs_parse_request(r, tgs_req,
&krbtgt_etype,
from, from_addr,
- &csec, &cusec,
- &auth_data);
+ &csec, &cusec);
if (ret == HDB_ERR_NOT_FOUND_HERE) {
/* kdc_log() is called in tgs_parse_request() */
goto out;
ret = tgs_build_reply(r,
krbtgt_etype,
- &auth_data,
from_addr);
if (ret) {
kdc_log(r->context, config, 4,
if (r->explicit_armor_pac)
krb5_pac_free(r->context, r->explicit_armor_pac);
krb5_free_keyblock_contents(r->context, &r->reply_key);
+ krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
krb5_free_keyblock_contents(r->context, &r->strengthen_key);
if (r->ticket)
_kdc_free_fast_state(&r->fast);
krb5_pac_free(r->context, r->pac);
- if (auth_data) {
- free_AuthorizationData(auth_data);
- free(auth_data);
- }
-
return ret;
}
goto out;
}
+ if (b->enc_authorization_data && r->rk_is_subkey == 0) {
+ krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
+ ret = krb5_copy_keyblock_contents(r->context,
+ &evidence_tkt.key,
+ &r->enc_ad_key);
+ if (ret)
+ goto out;
+ }
+
kdc_log(r->context, r->config, 4, "constrained delegation for %s "
"from %s (%s) to %s", s4ucname, r->cname, s4usname, r->sname);
r->pac_attributes = s4u_pac_attributes;
+ r->et.authtime = evidence_tkt.authtime;
+
out:
if (s4u_client)
_kdc_free_ent(r->context, s4u_clientdb, s4u_client);
sz += 2;
break;
default:
- if (!isalnum(c))
+ if (!isalnum((unsigned char)c))
sz += 2;
}
first = 0;
will set up new credentials caches, and AFS PAG, and then run the given
command.
When it finishes the credentials will be removed.
+.Sh CREDENTIALS CACHE TYPES
+Heimdal supports a number of credentials cache types:
+.Bl -tag -width Ds
+.It FILE
+Uses a file per-cache with a binary format common to other Kerberos
+implementations.
+.It DIR
+Uses a directory with multiple files, one per-cache in a collection.
+.It SCC
+Uses a SQLite3 database with multiple caches in the database.
+.It KEYRING
+Uses a Linux keyring.
+.It KCM
+Uses a inter-process communications (IPC) to talk to a daemon typically named
+.Nm kcm .
+.It API
+Uses KCM or else a shared object that implements the "CCAPI".
+.It MEMORY
+Uses in-process memory (which disappears on process exit, so this if of little
+use in this program,
+.Nm
+).
+.El
+.Sh CREDENTIALS CACHE COLLECTIONS
+Every credentials cache's name consists of its cache type (e.g.,
+FILE), a possibly-optional collection name, and a possibly
+optional "subsidiary" name naming a single cache in the
+collection.
+.Pp
+The convention in Heimdal is that a cache's subsidiary cache name
+is the name of the client principal whose credentials are
+expected to be stored and found in that cache, with the following
+characters replaced with a hyphen: slash, backslash, colon, and
+plus.
+.Pp
+The caches in a credentials cache collection can be listed by the
+.Xr klist 1
+command.
+The
+.Sq FILE
+credentials cache type supports listing of caches in the
+collection only when the
+.Ql enable_file_cache_iteration
+is set to
+.Ql yes
+in the
+.Ql [libdefaults]
+section of
+.Xr krb5.conf 5 .
+.Sh CREDENTIALS CACHE NAMES
+The general syntax for credentials cache names is
+.Dl TYPE:[collection-name][:subsidiary]
+except that for the FILE type it is
+.Dl FILE:collection-name[+subsidiary]
+and for the KEYRING type it is:
+.Dl KEYRING:[anchor:][collection[:subsidiary]]
+where the collection name is free-form and the anchor is one of
+.Sq process ,
+.Sq thread ,
+or
+.Sq legacy .
+.Pp
+The collection name is always absent for the
+.Ql MEMORY
+credentials cache type.
+.Pp
+When the collection name is absent then the default collection
+for the given credentials cache type is used, which are:
+.Bl -tag -compact
+.It Ql /tmp/krb5cc_{UID}
+for FILE caches, where {UID} is a numeric user ID
+.It Ql /tmp/krb5cc_{UID}_dir
+for DIR caches, where {UID} is a numeric user ID
+.It Ql /tmp/krb5scc_{UID}
+for SCC caches, where {UID} is a numeric user ID, and where the
+named file is a SQLite3 database file
+.It Ql {UID}
+for KCM caches, where {UID} is the user's numeric user ID
+.It <implementation-specific>
+for API (CCAPI) credentials caches
+.El
+.Pp
+The collection name is only optional for:
+.Ql DIR ,
+.Ql SCC ,
+.Ql KCM ,
+.Ql KEYRING
+and
+.Ql API
+credentials cache types.
+.Sh EXAMPLE CREDENTIALS CACHE NAMES
+.Bl -tag -width Ds
+.It Ql FILE:/tmp/cc
+this is a FILE cache in a file named
+.Ql /tmp/cc
+(the default would be
+.Ql /tmp/krb5cc_{UID} )
+.It Ql FILE:/tmp/cc+jane@TEST.H5L.SE
+.It Ql DIR:/tmp/ccdir
+this is a FILE cache named by
+.Ql /tmp/krb5cc_{UID}_dir/primary
+which will be of the form
+.Ql /tmp/ccdir/tkt.XXXXXX
+.It Ql DIR:/tmp/ccdir:jane@TEST.H5L.SE
+this is a FILE ccache named
+.Ql /tmp/ccdir/tkt.jane@TEST.H5L.SE
+.It Ql DIR::jane@TEST.H5L.SE
+this is a FILE ccache named
+.Ql /tmp/krb5cc_{UID}_dir/tkt.jane@TEST.H5L.SE
+where {UID} is the user's numeric identifier
+.It Ql SCC:
+this is the current primary cache in the SQLite3 database named
+.Ql /tmp/krb5scc_{UID}
+.It Ql SCC:/tmp/ccdb
+this is the current primary cache in the SQLite3 database named
+.Ql /tmp/ccdb
+.It Ql SCC:/tmp/ccdb:jane@TEST.H5L.SE
+this is the cache
+.Dq named jane@TEST.H5L.SE
+in the SQLite3 database
+named
+.Ql /tmp/ccdb
+.It Ql SCC::jane@TEST.H5L.SE
+this is the cache named
+.Dq jane@TEST.H5L.SE
+in the SQLite3 database named
+.Ql /tmp/krb5scc_{UID}
+.It Ql KEYRING:
+this is the primary cache in the default KEYRING collection for
+the running user
+.It Ql KEYRING:foo
+this is the primary cache in the KEYRING collection named
+.Dq foo
+.It Ql KEYRING:foo:jane@TEST.H5L.SE
+this is the cache named
+.Dq jane@TEST.H5L.SE
+in the KEYRING collection named
+.Dq foo
+.It Ql KCM:
+this is the primary cache in the default KCM collection for the
+running user
+.It Ql KCM:12345
+this is the primary cache in the default KCM collection for the
+user whose numeric identifier is 12345
+.It Ql KCM:jane@TEST.H5L.SE
+this is the cache named
+.Dq jane@TEST.H5L.SE
+in the default KCM collection for the running user
+.It Ql KCM:12345:jane@TEST.H5L.SE
+this is the cache named
+.Dq jane@TEST.H5L.SE
+in the default KCM collection for the given user
+.It Ql API:
+this is the primary cache in the default API collection for the
+running user
+.It Ql API:foo
+this is the primary cache in the API collection named
+.Dq foo
+.It Ql API:foo:jane@TEST.H5L.SE
+this is the cache named
+.Dq jane@TEST.H5L.SE
+in the KEYRING collection named
+.Dq foo
+.El
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev KRB5CCNAME
.Xr kdestroy 1 ,
.Xr klist 1 ,
.Xr kswitch 1 ,
+.Xr kcm 8 ,
.Xr krb5_appdefault 3 ,
.Xr krb5.conf 5
.\".Sh STANDARDS
ret = krb5_init_context(&context);
if (ret == KRB5_CONFIG_BADFORMAT)
- errx(1, "krb5_init_context failed to parse configuration file");
+ krb5_err(context, 1, ret, "Failed to parse configuration file");
+ else if (ret == EISDIR)
+ /* We use EISDIR to mean "not a regular file" */
+ krb5_errx(context, 1,
+ "Failed to read configuration file: not a regular file");
else if (ret)
- errx(1, "krb5_init_context failed: %d", ret);
+ krb5_err(context, 1, ret, "Failed to read configuration file");
if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
usage(1);
s = str.data;
printf("\"");
for (n = 0; n < str.length; n++) {
- if (isprint((int)s[n]))
+ if (isprint(s[n]))
printf ("%c", s[n]);
else
printf ("#%02x", s[n]);
gen_upper = strdup(s->gen_name);
len = strlen(gen_upper);
for (i = 0; i < len; i++)
- gen_upper[i] = toupper((int)s->gen_name[i]);
+ gen_upper[i] = toupper((unsigned char)s->gen_name[i]);
fprintf (headerfile, "} */\n");
fprintf (headerfile,
/* A drive letter path might be absolute */
if (len > 3
- && isalpha(path[0])
+ && isalpha((unsigned char)path[0])
&& path[1] == ':'
&& ISPATHSEP(path[2]))
return 1;
*err_message = "unmatched }";
return 2048;
} else if (strncmp(p, "include", sizeof("include") - 1) == 0 &&
- isspace(p[sizeof("include") - 1])) {
+ isspace((unsigned char)p[sizeof("include") - 1])) {
p += sizeof("include");
- while (isspace(*p))
+ while (isspace((unsigned char)*p))
p++;
if (!is_absolute_path(p)) {
heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT,
if (ret)
return ret;
} else if (strncmp(p, "includedir", sizeof("includedir") - 1) == 0 &&
- isspace(p[sizeof("includedir") - 1])) {
+ isspace((unsigned char)p[sizeof("includedir") - 1])) {
p += sizeof("includedir");
- while (isspace(*p))
+ while (isspace((unsigned char)*p))
p++;
if (!is_absolute_path(p)) {
heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT,
* so we're safe. Anyone changing this if condition here should
* be aware.
*/
- if (!isalnum(*p) && *p != '_' && *p != '-' &&
+ if (!isalnum((unsigned char)*p) && *p != '_' && *p != '-' &&
strcmp(p, ".conf") != 0) {
is_valid = 0;
break;
return 0;
}
+static int
+is_devnull(struct stat *st)
+{
+#ifdef WIN32
+ return 0;
+#else
+ struct stat devnullst;
+
+ if (stat("/dev/null", &devnullst) == -1)
+ return 0;
+ return st->st_dev == devnullst.st_dev && st->st_ino == devnullst.st_ino;
+#endif
+}
+
+HEIMDAL_THREAD_LOCAL int config_include_depth = 0;
+
/**
* Parse a configuration file and add the result into res. This
* interface can be used to parse several configuration files into one
* @ingroup heim_support
*/
-HEIMDAL_THREAD_LOCAL int config_include_depth = 0;
-
heim_error_code
heim_config_parse_file_multi(heim_context context,
const char *fname,
goto out;
}
- if (!S_ISREG(st.st_mode)) {
+ if (!S_ISREG(st.st_mode) && !is_devnull(&st)) {
(void) fclose(f.f);
heim_set_error_message(context, EISDIR, "not a regular file %s: %s",
fname, strerror(EISDIR));
return ENOMEM;
*arg++ = msg;
}
- if (context && do_errtext) {
+ if (do_errtext) {
strlcat(xfmt, "%s", sizeof(xfmt));
err_str = heim_get_error_message(context, code);
gss_OID oid = GSS_C_NO_OID;
size_t namelen = strlen(name);
- if (isdigit(name[0]) && _gss_string_to_oid(name, &oid) == 0)
+ if (isdigit((unsigned char)name[0]) &&
+ _gss_string_to_oid(name, &oid) == 0)
return oid;
_gss_load_mech();
/* normalise name to uppercase XXX UTF-8 OK? */
for (i = 0; i < len; i++) {
- ((char *)name->NetbiosName.value)[i] =
- toupper(((char *)name->NetbiosName.value)[i]);
+ ((unsigned char *)name->NetbiosName.value)[i] =
+ toupper(((unsigned char *)name->NetbiosName.value)[i]);
}
if (dnsName != NULL && dnsName[0] != '\0') {
i = 0;
for (p = str; *p != '\0'; p++) {
- if (isxdigit((int)*p))
+ if (isxdigit((unsigned char)*p))
i++;
- else if (isspace((int)*p))
+ else if (isspace((unsigned char)*p))
;
else
return NULL;
i = 0;
f = 0;
for (rp = dst, p = str; *p != '\0'; p++) {
- if (isxdigit((int)*p)) {
+ if (isxdigit((unsigned char)*p)) {
if (!f) {
b[0] = *p;
f = 1;
strncmp(s, "../", sizeof("../") - 1) == 0)
return 1;
#ifdef WIN32
- if (s[0] == '\\' || (isalpha(s[0]) && s[0] == ':') ||
+ if (s[0] == '\\' || (isalpha((unsigned char)s[0]) && s[0] == ':') ||
strncmp(s, ".\\", sizeof(".\\") - 1) == 0 ||
strncmp(s, "\\\\", sizeof("\\\\") - 1) == 0)
return 1;
p = strchr(buf, ':');
if (p) {
*p++ = '\0';
- while (isspace((int)*p))
+ while (isspace((unsigned char)*p))
p++;
ret = hx509_pem_add_header(&headers, buf, p);
if (ret)
if (auth_context) {
krb5_auth_con_free(context, auth_context);
auth_context = NULL;
- get_creds(context, &ccache, master);
}
+ get_creds(context, &ccache, master);
if (verbose)
krb5_warnx(context, "authenticating to master");
ret = krb5_sendauth (context, &auth_context, &master_fd,
return EINVAL;
if (consumed < 1)
return EINVAL;
- while (isspace(val[consumed]))
+ while (isspace((unsigned char)val[consumed]))
consumed++;
if (val[consumed] != '\0')
return EINVAL;
}
if (consumed < 1)
return EINVAL;
- while (isspace(val[consumed]))
+ while (isspace((unsigned char)val[consumed]))
consumed++;
if (val[consumed] != '\0')
return EINVAL;
}
} while (nxt);
- while (isspace(*p))
+ while (isspace((unsigned char)*p))
p++;
if (*p == '#') {
p = nxt;
val = strpbrk(p, " \t");
if (val) {
*(val++) = '\0';
- while (isspace(*val))
+ while (isspace((unsigned char)*val))
val++;
}
ret = eval_recipe1(sp, typ, val);
#ifdef _WIN32
/* Is drive letter? */
- if (isalpha(prefix[0]) && prefix[1] == ':')
+ if (isalpha((unsigned char)prefix[0]) && prefix[1] == ':')
return &krb5_fcc_ops;
#endif
struct _krb5_key_data *,
struct _krb5_encryption_type *);
-/*
+/*
* Converts etype to a user readable string and sets as a side effect
* the krb5_error_message containing this string. Returns
* KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
if(e == NULL) {
return unsupported_enctype (context, etype);
}
- *keytype = e->keytype->type; /* XXX */
+ *keytype = (krb5_keytype)e->keytype->type;
return 0;
}
}
l = len - et->confoundersize;
memmove(p, p + et->confoundersize, l);
- result->data = realloc(p, l);
- if(result->data == NULL && l != 0) {
- free(p);
- return krb5_enomem(context);
- }
+ result->data = p;
result->length = l;
return 0;
}
l = len - et->confoundersize;
memmove(p, p + et->blocksize + et->confoundersize, l);
- result->data = realloc(p, l);
- if(result->data == NULL && l != 0) {
- free(p);
- return krb5_enomem(context);
- }
+ result->data = p;
result->length = l;
return 0;
}
}
l = len - et->confoundersize - checksum_sz;
memmove(p, p + et->confoundersize + checksum_sz, l);
- result->data = realloc(p, l);
- if(result->data == NULL && l != 0) {
- free(p);
- return krb5_enomem(context);
- }
+ result->data = p;
result->length = l;
return 0;
}
}
memmove (p, p + cksum_sz + et->confoundersize, sz);
- result->data = realloc(p, sz);
- if(result->data == NULL && sz != 0) {
- free(p);
- return krb5_enomem(context);
- }
+ result->data = p;
result->length = sz;
return 0;
}
*
*/
- if (*res == '\0' || (res[0] == ':' && res[1] == '\0')) {
+ if (res == NULL || *res == '\0' || (res[0] == ':' && res[1] == '\0')) {
/* XXX Why not? */
krb5_set_error_message(context, KRB5_CC_FORMAT,
N_("\"DIR:\" is not a valid ccache name", ""));
/* Lower-case the hostname, because that's the convention */
for (cp = remote_host; *cp; cp++)
- if (isupper((int) (*cp)))
- *cp = tolower((int) (*cp));
+ if (isupper((unsigned char) (*cp)))
+ *cp = tolower((unsigned char) (*cp));
/*
* If there is only one name canon rule and it says to
tolower_str(char *s)
{
for (; *s != '\0'; s++) {
- if (isupper(*s))
+ if (isupper((unsigned char)*s))
*s = tolower_ascii(*s);
}
}
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
static inline void
-swapfunc(a, b, n, swaptype)
- char *a, *b;
- int n, swaptype;
+swapfunc(char *a, char *b, int n, int swaptype)
{
if(swaptype <= 1)
swapcode(long, a, b, n)
if (c->num_rows > j) {
char *header = c->header;
- while (isspace((int)header[0])) /* trim off prefixed whitespace */
+ while (isspace((unsigned char)header[0])) /* trim off prefixed whitespace */
header++;
p = rk_strpoolprintf(p, "%s\"%s\" : \"%s\"",
comma ? "," : "", header,
(*state->append_char) (state, ' ');
++len;
}
- return 0;
+ return len;
}
/*
switch (c) {
case 'c' :
- append_char(state, va_arg(ap, int), width, flags);
- ++len;
+ len += append_char(state, va_arg(ap, int), width, flags);
break;
case 's' :
len += append_string(state,
{
FILE *f;
char buf[1024];
- char filename[256] = "NormalizationTest.txt";
+ const char *fn = "NormalizationTest.txt";
unsigned failures = 0;
unsigned lineno = 0;
if (argc > 2)
errx(1, "usage: %s [file]", argv[0]);
else if (argc == 2)
- strlcpy(filename, argv[1], sizeof(filename));
+ fn = argv[1];
- f = fopen(filename, "r");
+ f = fopen(fn, "r");
if (f == NULL) {
const char *srcdir = getenv("srcdir");
if (srcdir != NULL) {
- char longname[256];
- snprintf(longname, sizeof(longname), "%s/%s", srcdir, filename);
- f = fopen(longname, "r");
+ char *long_fn = NULL;
+ if (asprintf(&long_fn, "%s/%s", srcdir, fn) == -1 ||
+ long_fn == NULL)
+ errx(1, "Out of memory");
+ f = fopen(long_fn, "r");
+ free(long_fn);
}
if (f == NULL)
- err(1, "open %s", filename);
+ err(1, "open %s", fn);
}
while (fgets(buf, sizeof(buf), f) != NULL) {
lineno++;