summaryrefslogtreecommitdiff
path: root/src/providers
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2012-10-18 16:34:35 +0200
committerSumit Bose <sbose@redhat.com>2012-10-26 10:32:05 +0200
commitdca03a97f4e1532ee2f2cbd26b1538ab6ccf18f7 (patch)
treee581a434e3ae95d078ce05d27d90318d1757af20 /src/providers
parent916674f6c54a64980f181790befe861a6e2b8daf (diff)
downloadsssd-dca03a97f4e1532ee2f2cbd26b1538ab6ccf18f7.tar.gz
sssd-dca03a97f4e1532ee2f2cbd26b1538ab6ccf18f7.tar.bz2
sssd-dca03a97f4e1532ee2f2cbd26b1538ab6ccf18f7.zip
krb5_child: send PAC to PAC responder
If the authenticated user comes from a different realm the service ticket which was returned during the validation of the TGT is used to extract the PAC which is send to the pac responder for evaluation.
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/krb5/krb5_child.c140
1 files changed, 139 insertions, 1 deletions
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 6e27df0d..4bfbf4bf 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -36,6 +36,7 @@
#include "providers/dp_backend.h"
#include "providers/krb5/krb5_auth.h"
#include "providers/krb5/krb5_utils.h"
+#include "sss_cli.h"
#define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
@@ -100,6 +101,124 @@ struct krb5_req {
static krb5_context krb5_error_ctx;
#define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
+static krb5_error_code extract_and_send_pac(struct krb5_req *kr,
+ krb5_ccache ccache,
+ krb5_principal server_principal,
+ krb5_principal client_principal,
+ krb5_keytab keytab)
+{
+ krb5_error_code kerr;
+ krb5_creds mcred;
+ krb5_creds cred;
+ krb5_authdata **pac_authdata = NULL;
+ krb5_pac pac = NULL;
+ struct sss_cli_req_data sss_data;
+ int ret;
+ int errnop;
+ krb5_ticket *ticket = NULL;
+ krb5_keytab_entry entry;
+
+ memset(&entry, 0, sizeof(entry));
+ memset(&mcred, 0, sizeof(mcred));
+ memset(&cred, 0, sizeof(mcred));
+
+ mcred.server = server_principal;
+ mcred.client = client_principal;
+
+ kerr = krb5_cc_retrieve_cred(kr->ctx, ccache, 0, &mcred, &cred);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_cc_retrieve_cred failed.\n"));
+ goto done;
+ }
+
+ kerr = krb5_decode_ticket(&cred.ticket, &ticket);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_decode_ticket failed.\n"));
+ goto done;
+ }
+
+ kerr = krb5_server_decrypt_ticket_keytab(kr->ctx, keytab, ticket);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_server_decrypt_ticket_keytab failed.\n"));
+ goto done;
+ }
+
+ kerr = sss_krb5_find_authdata(kr->ctx,
+ ticket->enc_part2->authorization_data, NULL,
+ KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_find_authdata failed.\n"));
+ goto done;
+ }
+
+ if (pac_authdata == NULL || pac_authdata[0] == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("No PAC authdata available.\n"));
+ kerr = ENOENT;
+ goto done;
+ }
+
+ if (pac_authdata[1] != NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("More than one PAC autdata found.\n"));
+ kerr = EINVAL;
+ goto done;
+ }
+
+ kerr = krb5_pac_parse(kr->ctx, pac_authdata[0]->contents,
+ pac_authdata[0]->length, &pac);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_pac_parse failed.\n"));
+ goto done;
+ }
+
+ kerr = krb5_kt_get_entry(kr->ctx, keytab, ticket->server,
+ ticket->enc_part.kvno, ticket->enc_part.enctype,
+ &entry);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_kt_get_entry failed.\n"));
+ goto done;
+ }
+
+ kerr = krb5_pac_verify(kr->ctx, pac, 0, NULL, &entry.key, NULL);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("krb5_pac_verify failed.\n"));
+ goto done;
+ }
+
+ ret = unsetenv("_SSS_LOOPS");
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to unset _SSS_LOOPS, "
+ "sss_pac_make_request will most certainly fail.\n"));
+ }
+
+ sss_data.len = pac_authdata[0]->length;
+ sss_data.data = pac_authdata[0]->contents;
+
+ ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
+ NULL, NULL, &errnop);
+ if (ret != NSS_STATUS_SUCCESS || errnop != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_pac_make_request failed [%d][%d].\n",
+ ret, errnop));
+ kerr = EIO;
+ goto done;
+ }
+
+ kerr = 0;
+
+done:
+ if (entry.magic != 0) {
+ krb5_free_keytab_entry_contents(kr->ctx, &entry);
+ }
+ krb5_pac_free(kr->ctx, pac);
+ krb5_free_authdata(kr->ctx, pac_authdata);
+ if (ticket != NULL) {
+ krb5_free_ticket(kr->ctx, ticket);
+ }
+
+ krb5_free_cred_contents(kr->ctx, &cred);
+
+ return kerr;
+}
+
static void sss_krb5_expire_callback_func(krb5_context context, void *data,
krb5_timestamp password_expiration,
krb5_timestamp account_expiration,
@@ -696,6 +815,7 @@ static krb5_error_code validate_tgt(struct krb5_req *kr)
krb5_verify_init_creds_opt opt;
krb5_principal validation_princ = NULL;
bool realm_entry_found = false;
+ krb5_ccache validation_ccache = NULL;
memset(&keytab, 0, sizeof(keytab));
kerr = krb5_kt_resolve(kr->ctx, kr->keytab, &keytab);
@@ -778,7 +898,7 @@ static krb5_error_code validate_tgt(struct krb5_req *kr)
krb5_verify_init_creds_opt_init(&opt);
kerr = krb5_verify_init_creds(kr->ctx, kr->creds, validation_princ, keytab,
- NULL, &opt);
+ &validation_ccache, &opt);
if (kerr == 0) {
DEBUG(SSSDBG_TRACE_FUNC, ("TGT verified using key for [%s].\n",
@@ -786,9 +906,27 @@ static krb5_error_code validate_tgt(struct krb5_req *kr)
} else {
DEBUG(SSSDBG_CRIT_FAILURE ,("TGT failed verification using key " \
"for [%s].\n", principal));
+ goto done;
+ }
+
+ /* Try to find and send the PAC to the PAC responder for principals which
+ * do not belong to our realm. Failures are not critical. */
+ if (kr->upn_from_different_realm) {
+ kerr = extract_and_send_pac(kr, validation_ccache, validation_princ,
+ kr->creds->client, keytab);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("extract_and_send_pac failed, group " \
+ "membership for user with principal [%s] " \
+ "might not be correct.\n", kr->name));
+ kerr = 0;
+ }
}
done:
+ if (validation_ccache != NULL) {
+ krb5_cc_destroy(kr->ctx, validation_ccache);
+ }
+
if (krb5_kt_close(kr->ctx, keytab) != 0) {
DEBUG(SSSDBG_MINOR_FAILURE, ("krb5_kt_close failed"));
}