return code;
}
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
-static krb5_error_code ks_verify_pac(krb5_context context,
- unsigned int flags,
- krb5_const_principal client_princ,
- krb5_db_entry *client,
- krb5_db_entry *server,
- krb5_db_entry *krbtgt,
- krb5_keyblock *server_key,
- krb5_keyblock *krbtgt_key,
- krb5_timestamp authtime,
- krb5_authdata **tgt_auth_data,
- krb5_pac *pac)
-{
- struct mit_samba_context *mit_ctx;
- krb5_authdata **authdata = NULL;
- krb5_pac ipac = NULL;
- DATA_BLOB logon_data = { NULL, 0 };
- krb5_error_code code;
-
- mit_ctx = ks_get_context(context);
- if (mit_ctx == NULL) {
- return KRB5_KDB_DBNOTINITED;
- }
-
- /* find the existing PAC, if present */
- code = krb5_find_authdata(context,
- tgt_auth_data,
- NULL,
- KRB5_AUTHDATA_WIN2K_PAC,
- &authdata);
- if (code != 0) {
- return code;
- }
-
- /* no pac data */
- if (authdata == NULL) {
- return 0;
- }
-
- SMB_ASSERT(authdata[0] != NULL);
-
- if (authdata[1] != NULL) {
- code = KRB5KDC_ERR_BADOPTION; /* XXX */
- goto done;
- }
-
- code = krb5_pac_parse(context,
- authdata[0]->contents,
- authdata[0]->length,
- &ipac);
- if (code != 0) {
- goto done;
- }
-
- /* TODO: verify this is correct
- *
- * In the constrained delegation case, the PAC is from a service
- * ticket rather than a TGT; we must verify the server and KDC
- * signatures to assert that the server did not forge the PAC.
- */
- if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
- code = krb5_pac_verify(context,
- ipac,
- authtime,
- client_princ,
- server_key,
- krbtgt_key);
- } else {
- code = krb5_pac_verify(context,
- ipac,
- authtime,
- client_princ,
- krbtgt_key,
- NULL);
- }
- if (code != 0) {
- goto done;
- }
-
- /* check and update PAC */
- code = krb5_pac_parse(context,
- authdata[0]->contents,
- authdata[0]->length,
- pac);
- if (code != 0) {
- goto done;
- }
-
- code = mit_samba_reget_pac(mit_ctx,
- context,
- flags,
- client_princ,
- client,
- server,
- krbtgt,
- krbtgt_key,
- pac);
-
-done:
- krb5_free_authdata(context, authdata);
- krb5_pac_free(context, ipac);
- free(logon_data.data);
-
- return code;
-}
-
-krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
- unsigned int flags,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_db_entry *client,
- krb5_db_entry *server,
- krb5_db_entry *krbtgt,
- krb5_db_entry *local_krbtgt,
- krb5_keyblock *client_key,
- krb5_keyblock *server_key,
- krb5_keyblock *krbtgt_key,
- krb5_keyblock *local_krbtgt_key,
- krb5_keyblock *session_key,
- krb5_timestamp authtime,
- krb5_authdata **tgt_auth_data,
- void *authdata_info,
- krb5_data ***auth_indicators,
- krb5_authdata ***signed_auth_data)
-{
- krb5_const_principal ks_client_princ = NULL;
- krb5_db_entry *client_entry = NULL;
- krb5_authdata **pac_auth_data = NULL;
- krb5_authdata **authdata = NULL;
- krb5_boolean is_as_req;
- krb5_error_code code;
- krb5_pac pac = NULL;
- krb5_data pac_data;
- bool with_pac = false;
- bool generate_pac = false;
- char *client_name = NULL;
-
-
- krbtgt = krbtgt == NULL ? local_krbtgt : krbtgt;
- krbtgt_key = krbtgt_key == NULL ? local_krbtgt_key : krbtgt_key;
-
- /* FIXME: We don't support S4U yet */
- if (flags & KRB5_KDB_FLAGS_S4U) {
- return KRB5_KDB_DBTYPE_NOSUP;
- }
-
- is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
-
- /*
- * When using s4u2proxy client_princ actually refers to the proxied user
- * while client->princ to the proxy service asking for the TGS on behalf
- * of the proxied user. So always use client_princ in preference.
- *
- * Note that when client principal is not NULL, client entry might be
- * NULL for cross-realm case, so we need to make sure to not
- * dereference NULL pointer here.
- */
- if (client_princ != NULL) {
- ks_client_princ = client_princ;
- if (!is_as_req) {
- krb5_boolean is_equal = false;
-
- if (client != NULL && client->princ != NULL) {
- is_equal =
- krb5_principal_compare(context,
- client_princ,
- client->princ);
- }
-
- /*
- * When client principal is the same as supplied client
- * entry, don't fetch it.
- */
- if (!is_equal) {
- code = ks_get_principal(context,
- ks_client_princ,
- 0,
- &client_entry);
- if (code != 0) {
- (void)krb5_unparse_name(context,
- ks_client_princ,
- &client_name);
-
- DBG_DEBUG("We didn't find the client "
- "principal [%s] in our "
- "database.\n",
- client_name);
- SAFE_FREE(client_name);
-
- /*
- * If we didn't find client_princ in our
- * database it might be from another
- * realm.
- */
- client_entry = NULL;
- }
- }
- }
- } else {
- if (client == NULL) {
- *signed_auth_data = NULL;
- return 0;
- }
- ks_client_princ = client->princ;
- }
-
- if (client_entry == NULL) {
- client_entry = client;
- }
-
- if (is_as_req) {
- with_pac = mit_samba_princ_needs_pac(client_entry);
- } else {
- with_pac = mit_samba_princ_needs_pac(server);
- }
-
- code = krb5_unparse_name(context,
- client_princ,
- &client_name);
- if (code != 0) {
- goto done;
- }
-
- if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC) != 0) {
- generate_pac = true;
- }
-
- DBG_DEBUG("*** Sign data for client principal: %s [%s %s%s]\n",
- client_name,
- is_as_req ? "AS-REQ" : "TGS_REQ",
- with_pac ? is_as_req ? "WITH_PAC" : "FIND_PAC" : "NO_PAC",
- generate_pac ? " GENERATE_PAC" : "");
-
- /*
- * Generate PAC for the AS-REQ or check or generate one for the TGS if
- * needed.
- */
- if (with_pac && generate_pac) {
- DBG_DEBUG("Generate PAC for AS-REQ [%s]\n", client_name);
-
- code = krb5_pac_init(context, &pac);
- if (code != 0) {
- goto done;
- }
-
- code = ks_get_pac(context,
- flags,
- client_entry,
- server,
- NULL,
- &pac);
- if (code != 0) {
- goto done;
- }
- } else if (with_pac && !is_as_req) {
- /*
- * Find the PAC in the TGS, if one exists.
- */
- code = krb5_find_authdata(context,
- tgt_auth_data,
- NULL,
- KRB5_AUTHDATA_WIN2K_PAC,
- &pac_auth_data);
- if (code != 0) {
- DBG_ERR("krb5_find_authdata failed: %d\n", code);
- goto done;
- }
- DBG_DEBUG("Found PAC data for TGS-REQ [%s]\n", client_name);
-
- if (pac_auth_data != NULL && pac_auth_data[0] != NULL) {
- if (pac_auth_data[1] != NULL) {
- DBG_ERR("Invalid PAC data!\n");
- code = KRB5KDC_ERR_BADOPTION;
- goto done;
- }
-
- DBG_DEBUG("Verify PAC for TGS [%s]\n",
- client_name);
-
- code = ks_verify_pac(context,
- flags,
- ks_client_princ,
- client_entry,
- server,
- krbtgt,
- server_key,
- krbtgt_key,
- authtime,
- tgt_auth_data,
- &pac);
- if (code != 0) {
- goto done;
- }
- } else {
- if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
- DBG_DEBUG("Generate PAC for constrained"
- "delegation TGS [%s]\n",
- client_name);
-
- code = krb5_pac_init(context, &pac);
- if (code != 0) {
- goto done;
- }
-
- code = ks_get_pac(context,
- flags,
- client_entry,
- server,
- NULL,
- &pac);
- if (code != 0 && code != ENOENT) {
- goto done;
- }
- }
- }
- }
-
- if (pac == NULL) {
- DBG_DEBUG("No PAC data - we're done [%s]\n", client_name);
- *signed_auth_data = NULL;
- code = 0;
- goto done;
- }
-
- DBG_DEBUG("Signing PAC for %s [%s]\n",
- is_as_req ? "AS-REQ" : "TGS-REQ",
- client_name);
- code = krb5_pac_sign(context, pac, authtime, ks_client_princ,
- server_key, krbtgt_key, &pac_data);
- if (code != 0) {
- DBG_ERR("krb5_pac_sign failed: %d\n", code);
- goto done;
- }
-
- authdata = calloc(2, sizeof(krb5_authdata *));
- if (authdata == NULL) {
- goto done;
- }
-
- authdata[0] = malloc(sizeof(krb5_authdata));
- if (authdata[0] == NULL) {
- goto done;
- }
-
- /* put in signed data */
- authdata[0]->magic = KV5M_AUTHDATA;
- authdata[0]->ad_type = KRB5_AUTHDATA_WIN2K_PAC;
- authdata[0]->contents = (krb5_octet *)pac_data.data;
- authdata[0]->length = pac_data.length;
-
- code = krb5_encode_authdata_container(context,
- KRB5_AUTHDATA_IF_RELEVANT,
- authdata,
- signed_auth_data);
- if (code != 0) {
- goto done;
- }
-
- code = 0;
-
-done:
- if (client_entry != NULL && client_entry != client) {
- ks_free_principal(context, client_entry);
- }
- SAFE_FREE(client_name);
- krb5_free_authdata(context, authdata);
- krb5_pac_free(context, pac);
-
- return code;
-}
-#else /* KRB5_KDB_DAL_MAJOR_VERSION >= 9 */
static krb5_error_code ks_update_pac(krb5_context context,
int flags,
krb5_db_entry *client,
return code;
}
-#endif /* KRB5_KDB_DAL_MAJOR_VERSION */
krb5_error_code kdb_samba_db_check_allowed_to_delegate(krb5_context context,
krb5_const_principal client,
}
-#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
krb5_error_code kdb_samba_db_allowed_to_delegate_from(
krb5_context context,
krb5_const_principal client_principal,
return code;
}
-#endif
static void samba_bad_password_count(krb5_db_entry *client,
return ENOMEM;
}
-#if KRB5_KDB_API_VERSION >= 10
/*
* The MIT KDC code that wants the canonical name in all lookups, and
* takes care to canonicalize only when appropriate.
*/
sflags |= SDB_F_FORCE_CANON;
-#endif
-#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
if (kflags & KRB5_KDB_FLAG_REFERRAL_OK) {
sflags |= SDB_F_CANON;
}
sflags |= SDB_F_FOR_TGS_REQ;
}
}
-#else /* KRB5_KDB_DAL_MAJOR_VERSION < 9 */
- if (kflags & KRB5_KDB_FLAG_CANONICALIZE) {
- sflags |= SDB_F_CANON;
- }
- if (kflags & (KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY |
- KRB5_KDB_FLAG_INCLUDE_PAC)) {
- /*
- * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY is equal to
- * SDB_F_FOR_AS_REQ
- *
- * We use ANY to also allow AS_REQ for service principal names
- * This is supported by Windows.
- */
- sflags |= SDB_F_GET_ANY|SDB_F_FOR_AS_REQ;
- } else {
- int equal = smb_krb5_principal_is_tgs(ctx->context, principal);
- if (equal == -1) {
- return ENOMEM;
- }
-
- if (equal) {
- sflags |= SDB_F_GET_KRBTGT;
- } else {
- sflags |= SDB_F_GET_SERVER|SDB_F_FOR_TGS_REQ;
- }
- }
-#endif /* KRB5_KDB_DAL_MAJOR_VERSION */
/* always set this or the created_by data will not be populated by samba's
* backend and we will fail to parse the entry later */
return code;
}
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
-krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
- krb5_context context,
- int kdc_flags,
- krb5_const_principal client_principal,
- krb5_db_entry *client,
- krb5_db_entry *server,
- krb5_db_entry *krbtgt,
- krb5_keyblock *krbtgt_keyblock,
- krb5_pac *pac)
-{
- TALLOC_CTX *tmp_ctx;
- krb5_error_code code;
- struct samba_kdc_entry *client_skdc_entry = NULL;
- struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
- struct samba_kdc_entry *server_skdc_entry = NULL;
- struct samba_kdc_entry *delegated_proxy_entry = NULL;
- krb5_principal delegated_proxy_principal = NULL;
- krb5_pac new_pac = NULL;
- bool is_in_db = false;
- bool is_trusted = false;
- uint32_t flags = SAMBA_KDC_FLAG_SKIP_PAC_BUFFER;
-
- /* Create a memory context early so code can use talloc_stackframe() */
- tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
- if (tmp_ctx == NULL) {
- return ENOMEM;
- }
-
- if (client != NULL) {
- client_skdc_entry =
- talloc_get_type_abort(client->e_data,
- struct samba_kdc_entry);
- }
-
- if (server == NULL) {
- code = EINVAL;
- goto done;
- }
-
- server_skdc_entry =
- talloc_get_type_abort(server->e_data,
- struct samba_kdc_entry);
-
- if (krbtgt == NULL) {
- code = EINVAL;
- goto done;
- }
- krbtgt_skdc_entry =
- talloc_get_type_abort(krbtgt->e_data,
- struct samba_kdc_entry);
-
- code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
- &is_in_db,
- &is_trusted);
- if (code != 0) {
- goto done;
- }
-
- if (is_trusted) {
- flags |= SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED;
- }
-
- if (is_in_db) {
- flags |= SAMBA_KDC_FLAG_KRBTGT_IN_DB;
-
- }
-
- if (kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) {
- flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
- }
-
- if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
- flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
- delegated_proxy_entry = client_skdc_entry;
- delegated_proxy_principal = discard_const(client_principal);
- }
-
- code = samba_kdc_verify_pac(tmp_ctx,
- context,
- flags,
- client_skdc_entry,
- krbtgt_skdc_entry,
- NULL /* device */,
- NULL /* device_pac */,
- *pac);
- if (code != 0) {
- goto done;
- }
-
- /* Build an updated PAC */
- code = krb5_pac_init(context, &new_pac);
- if (code != 0) {
- goto done;
- }
-
- code = samba_kdc_update_pac(tmp_ctx,
- context,
- krbtgt_skdc_entry->kdc_db_ctx->samdb,
- krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
- flags,
- krbtgt_skdc_entry,
- client_skdc_entry,
- server->princ,
- server_skdc_entry,
- delegated_proxy_principal,
- delegated_proxy_entry,
- NULL /* delegated_proxy_pac */,
- NULL /* device_krbtgt */,
- NULL /* device */,
- NULL /* device_pac */,
- *pac,
- new_pac,
- NULL /* server_audit_info_out */,
- NULL /* status_out */);
- if (code != 0) {
- krb5_pac_free(context, new_pac);
- if (code == ENOATTR) {
- krb5_pac_free(context, *pac);
- *pac = NULL;
- code = 0;
- }
- goto done;
- }
-
- /* We now replace the pac */
- krb5_pac_free(context, *pac);
- *pac = new_pac;
-
-done:
- talloc_free(tmp_ctx);
- return code;
-}
-#else
krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
krb5_context context,
int kdc_flags,
talloc_free(tmp_ctx);
return code;
}
-#endif
/* provide header, function is exported but there are no public headers */
const krb5_db_entry *server,
krb5_const_principal target_principal)
{
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
- return KRB5KDC_ERR_BADOPTION;
-#else
struct samba_kdc_entry *server_skdc_entry =
talloc_get_type_abort(server->e_data, struct samba_kdc_entry);
krb5_error_code code;
target_principal);
return code;
-#endif
}
krb5_error_code mit_samba_check_allowed_to_delegate_from(
krb5_pac header_pac,
const krb5_db_entry *proxy)
{
-#if KRB5_KDB_DAL_MAJOR_VERSION < 8
- return KRB5KDC_ERR_POLICY;
-#else
struct samba_kdc_entry *proxy_skdc_entry =
talloc_get_type_abort(proxy->e_data, struct samba_kdc_entry);
krb5_error_code code;
proxy_skdc_entry);
return code;
-#endif
}
static krb5_error_code mit_samba_change_pwd_error(krb5_context context,