NTSTATUS cli_credentials_update_all_keytabs(TALLOC_CTX *parent_ctx) { TALLOC_CTX *mem_ctx; int ldb_ret; struct ldb_context *ldb; struct ldb_message **msgs; const char *attrs[] = { NULL }; struct cli_credentials *creds; const char *filter; NTSTATUS status; int i, ret; mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } /* Local secrets are stored in secrets.ldb */ ldb = secrets_db_connect(mem_ctx); if (!ldb) { DEBUG(1, ("Could not open secrets.ldb\n")); talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } /* search for the secret record, but only of things we can * actually update */ ldb_ret = gendb_search(ldb, mem_ctx, NULL, &msgs, attrs, "(&(objectClass=kerberosSecret)(|(secret=*)(ntPwdHash=*)))"); if (ldb_ret == -1) { DEBUG(1, ("Error looking for kerberos type secrets to push into a keytab:: %s", ldb_errstring(ldb))); talloc_free(mem_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } for (i=0; i < ldb_ret; i++) { /* Make a credentials structure from it */ creds = cli_credentials_init(mem_ctx); if (!creds) { DEBUG(1, ("cli_credentials_init failed!")); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(creds); filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_get_linearized(msgs[i]->dn)); status = cli_credentials_set_secrets(creds, NULL, filter); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to read secrets for keytab update for %s\n", filter)); continue; } ret = cli_credentials_update_keytab(creds); if (ret != 0) { DEBUG(1, ("Failed to update keytab for %s\n", filter)); continue; } } return NT_STATUS_OK; }
/** * Retrieve the domain SID from the secrets database. * @return pointer to a SID object if the SID could be obtained, NULL otherwise */ struct dom_sid *secrets_get_domain_sid(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, const char *domain, enum netr_SchannelType *sec_channel_type, char **errstring) { struct ldb_context *ldb; struct ldb_message *msg; int ldb_ret; const char *attrs[] = { "objectSid", "secureChannelType", NULL }; struct dom_sid *result = NULL; const struct ldb_val *v; enum ndr_err_code ndr_err; *errstring = NULL; ldb = secrets_db_connect(mem_ctx, lp_ctx); if (ldb == NULL) { DEBUG(5, ("secrets_db_connect failed\n")); return NULL; } ldb_ret = dsdb_search_one(ldb, ldb, &msg, ldb_dn_new(mem_ctx, ldb, SECRETS_PRIMARY_DOMAIN_DN), LDB_SCOPE_ONELEVEL, attrs, 0, SECRETS_PRIMARY_DOMAIN_FILTER, domain); if (ldb_ret != LDB_SUCCESS) { *errstring = talloc_asprintf(mem_ctx, "Failed to find record for %s in %s: %s: %s", domain, (char *) ldb_get_opaque(ldb, "ldb_url"), ldb_strerror(ldb_ret), ldb_errstring(ldb)); return NULL; } v = ldb_msg_find_ldb_val(msg, "objectSid"); if (v == NULL) { *errstring = talloc_asprintf(mem_ctx, "Failed to find a SID on record for %s in %s", domain, (char *) ldb_get_opaque(ldb, "ldb_url")); return NULL; } if (sec_channel_type) { int t; t = ldb_msg_find_attr_as_int(msg, "secureChannelType", -1); if (t == -1) { *errstring = talloc_asprintf(mem_ctx, "Failed to find secureChannelType for %s in %s", domain, (char *) ldb_get_opaque(ldb, "ldb_url")); return NULL; } *sec_channel_type = t; } result = talloc(mem_ctx, struct dom_sid); if (result == NULL) { talloc_free(ldb); return NULL; } ndr_err = ndr_pull_struct_blob(v, result, result, (ndr_pull_flags_fn_t)ndr_pull_dom_sid); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { *errstring = talloc_asprintf(mem_ctx, "Failed to parse SID on record for %s in %s", domain, (char *) ldb_get_opaque(ldb, "ldb_url")); talloc_free(result); talloc_free(ldb); return NULL; } return result; }
/** * Fill in credentials for the machine trust account, from the secrets database. * * @param cred Credentials structure to fill in * @retval NTSTATUS error detailing any failure */ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, const char *base, const char *filter) { TALLOC_CTX *mem_ctx; struct ldb_context *ldb; int ldb_ret; struct ldb_message **msgs; const char *attrs[] = { "secret", "priorSecret", "samAccountName", "flatname", "realm", "secureChannelType", "ntPwdHash", "msDS-KeyVersionNumber", "saltPrincipal", "privateKeytab", "krb5Keytab", NULL }; const char *machine_account; const char *password; const char *old_password; const char *domain; const char *realm; enum netr_SchannelType sct; const char *salt_principal; const char *keytab; /* ok, we are going to get it now, don't recurse back here */ cred->machine_account_pending = False; /* some other parts of the system will key off this */ cred->machine_account = True; mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password"); /* Local secrets are stored in secrets.ldb */ ldb = secrets_db_connect(mem_ctx); if (!ldb) { /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); DEBUG(1, ("Could not open secrets.ldb\n")); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } /* search for the secret record */ ldb_ret = gendb_search(ldb, mem_ctx, ldb_dn_new(mem_ctx, ldb, base), &msgs, attrs, "%s", filter); if (ldb_ret == 0) { DEBUG(1, ("Could not find entry to match filter: %s\n", filter)); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } else if (ldb_ret != 1) { DEBUG(1, ("Found more than one (%d) entry to match filter: %s\n", ldb_ret, filter)); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } password = ldb_msg_find_attr_as_string(msgs[0], "secret", NULL); old_password = ldb_msg_find_attr_as_string(msgs[0], "priorSecret", NULL); machine_account = ldb_msg_find_attr_as_string(msgs[0], "samAccountName", NULL); if (!machine_account) { DEBUG(1, ("Could not find 'samAccountName' in join record to domain: %s\n", cli_credentials_get_domain(cred))); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } salt_principal = ldb_msg_find_attr_as_string(msgs[0], "saltPrincipal", NULL); cli_credentials_set_salt_principal(cred, salt_principal); sct = ldb_msg_find_attr_as_int(msgs[0], "secureChannelType", 0); if (sct) { cli_credentials_set_secure_channel_type(cred, sct); } if (!password) { const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msgs[0], "ntPwdHash"); struct samr_Password hash; ZERO_STRUCT(hash); if (nt_password_hash) { memcpy(hash.hash, nt_password_hash->data, MIN(nt_password_hash->length, sizeof(hash.hash))); cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED); } else { cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); } } else { cli_credentials_set_password(cred, password, CRED_SPECIFIED); } domain = ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL); if (domain) { cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); } realm = ldb_msg_find_attr_as_string(msgs[0], "realm", NULL); if (realm) { cli_credentials_set_realm(cred, realm, CRED_SPECIFIED); } cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msgs[0], "msDS-KeyVersionNumber", 0)); /* If there was an external keytab specified by reference in * the LDB, then use this. Otherwise we will make one up * (chewing CPU time) from the password */ keytab = ldb_msg_find_attr_as_string(msgs[0], "krb5Keytab", NULL); if (keytab) { cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED); } else { keytab = ldb_msg_find_attr_as_string(msgs[0], "privateKeytab", NULL); if (keytab) { keytab = talloc_asprintf(mem_ctx, "FILE:%s", private_path(mem_ctx, keytab)); if (keytab) { cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED); } } } talloc_free(mem_ctx); return NT_STATUS_OK; }
/** * Fill in credentials for the machine trust account, from the secrets database. * * @param cred Credentials structure to fill in * @retval NTSTATUS error detailing any failure */ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, struct loadparm_context *lp_ctx, struct ldb_context *ldb, const char *base, const char *filter, time_t secrets_tdb_last_change_time, const char *secrets_tdb_password, char **error_string) { TALLOC_CTX *mem_ctx; int ldb_ret; struct ldb_message *msg; const char *machine_account; const char *password; const char *domain; const char *realm; enum netr_SchannelType sct; const char *salt_principal; char *keytab; const struct ldb_val *whenChanged; time_t lct; /* ok, we are going to get it now, don't recurse back here */ cred->machine_account_pending = false; /* some other parts of the system will key off this */ cred->machine_account = true; mem_ctx = talloc_named(cred, 0, "cli_credentials_set_secrets from ldb"); if (!ldb) { /* Local secrets are stored in secrets.ldb */ ldb = secrets_db_connect(mem_ctx, lp_ctx); if (!ldb) { *error_string = talloc_strdup(cred, "Could not open secrets.ldb"); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } } ldb_ret = dsdb_search_one(ldb, mem_ctx, &msg, ldb_dn_new(mem_ctx, ldb, base), LDB_SCOPE_SUBTREE, NULL, 0, "%s", filter); if (ldb_ret != LDB_SUCCESS) { *error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s", filter, base ? base : "", ldb_strerror(ldb_ret), ldb_errstring(ldb)); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } password = ldb_msg_find_attr_as_string(msg, "secret", NULL); whenChanged = ldb_msg_find_ldb_val(msg, "whenChanged"); if (!whenChanged || ldb_val_to_time(whenChanged, &lct) != LDB_SUCCESS) { /* This attribute is mandetory */ talloc_free(mem_ctx); return NT_STATUS_NOT_FOUND; } /* Don't set secrets.ldb info if the secrets.tdb entry was more recent */ if (lct < secrets_tdb_last_change_time) { talloc_free(mem_ctx); return NT_STATUS_NOT_FOUND; } if (lct == secrets_tdb_last_change_time && secrets_tdb_password && strcmp(password, secrets_tdb_password) != 0) { talloc_free(mem_ctx); return NT_STATUS_NOT_FOUND; } cli_credentials_set_password_last_changed_time(cred, lct); machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); if (!machine_account) { machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL); if (!machine_account) { const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL); if (!ldap_bind_dn) { *error_string = talloc_asprintf(cred, "Could not find 'samAccountName', " "'servicePrincipalName' or " "'ldapBindDn' in secrets record: %s", ldb_dn_get_linearized(msg->dn)); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } else { /* store bind dn in credentials */ cli_credentials_set_bind_dn(cred, ldap_bind_dn); } } } salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL); cli_credentials_set_salt_principal(cred, salt_principal); sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0); if (sct) { cli_credentials_set_secure_channel_type(cred, sct); } if (!password) { const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd"); struct samr_Password hash; ZERO_STRUCT(hash); if (nt_password_hash) { memcpy(hash.hash, nt_password_hash->data, MIN(nt_password_hash->length, sizeof(hash.hash))); cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED); } else { cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); } } else { cli_credentials_set_password(cred, password, CRED_SPECIFIED); } domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL); if (domain) { cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); } realm = ldb_msg_find_attr_as_string(msg, "realm", NULL); if (realm) { cli_credentials_set_realm(cred, realm, CRED_SPECIFIED); } if (machine_account) { cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); } cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0)); /* If there was an external keytab specified by reference in * the LDB, then use this. Otherwise we will make one up * (chewing CPU time) from the password */ keytab = keytab_name_from_msg(cred, ldb, msg); if (keytab) { cli_credentials_set_keytab_name(cred, lp_ctx, keytab, CRED_SPECIFIED); talloc_free(keytab); } talloc_free(mem_ctx); return NT_STATUS_OK; }