⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 password_hash.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 4 页
字号:
/*    ldb database module   Copyright (C) Simo Sorce  2004-2006   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006   Copyright (C) Andrew Tridgell 2004   Copyright (C) Stefan Metzmacher 2007   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.*//* *  Name: ldb * *  Component: ldb password_hash module * *  Description: correctly update hash values based on changes to sambaPassword and friends * *  Author: Andrew Bartlett *  Author: Stefan Metzmacher */#include "includes.h"#include "libcli/ldap/ldap_ndr.h"#include "ldb/include/ldb_errors.h"#include "ldb/include/ldb.h"#include "ldb/include/ldb_private.h"#include "librpc/gen_ndr/misc.h"#include "librpc/gen_ndr/samr.h"#include "libcli/auth/libcli_auth.h"#include "libcli/security/security.h"#include "system/kerberos.h"#include "auth/kerberos/kerberos.h"#include "system/time.h"#include "dsdb/samdb/samdb.h"#include "dsdb/common/flags.h"#include "dsdb/samdb/ldb_modules/password_modules.h"#include "librpc/ndr/libndr.h"#include "librpc/gen_ndr/ndr_drsblobs.h"#include "lib/crypto/crypto.h"#include "param/param.h"/* If we have decided there is reason to work on this request, then * setup all the password hash types correctly. * * If the administrator doesn't want the sambaPassword stored (set in the * domain and per-account policies) then we must strip that out before * we do the first operation. * * Once this is done (which could update anything at all), we * calculate the password hashes. * * This function must not only update the unicodePwd, dBCSPwd and * supplementalCredentials fields, it must also atomicly increment the * msDS-KeyVersionNumber.  We should be in a transaction, so all this * should be quite safe... * * Finally, if the administrator has requested that a password history * be maintained, then this should also be written out. * */struct ph_context {	enum ph_type {PH_ADD, PH_MOD} type;	enum ph_step {PH_ADD_SEARCH_DOM, PH_ADD_DO_ADD, PH_MOD_DO_REQ, PH_MOD_SEARCH_SELF, PH_MOD_SEARCH_DOM, PH_MOD_DO_MOD} step;	struct ldb_module *module;	struct ldb_request *orig_req;	struct ldb_request *dom_req;	struct ldb_reply *dom_res;	struct ldb_request *down_req;	struct ldb_request *search_req;	struct ldb_reply *search_res;	struct ldb_request *mod_req;	struct dom_sid *domain_sid;};struct domain_data {	bool store_cleartext;	uint_t pwdProperties;	uint_t pwdHistoryLength;	char *netbios_domain;	char *dns_domain;	char *realm;};struct setup_password_fields_io {	struct ph_context *ac;	struct domain_data *domain;	struct smb_krb5_context *smb_krb5_context;	/* infos about the user account */	struct {		uint32_t user_account_control;		const char *sAMAccountName;		const char *user_principal_name;		bool is_computer;	} u;	/* new credentials */	struct {		const char *cleartext;		struct samr_Password *nt_hash;		struct samr_Password *lm_hash;	} n;	/* old credentials */	struct {		uint32_t nt_history_len;		struct samr_Password *nt_history;		uint32_t lm_history_len;		struct samr_Password *lm_history;		const struct ldb_val *supplemental;		struct supplementalCredentialsBlob scb;		uint32_t kvno;	} o;	/* generated credentials */	struct {		struct samr_Password *nt_hash;		struct samr_Password *lm_hash;		uint32_t nt_history_len;		struct samr_Password *nt_history;		uint32_t lm_history_len;		struct samr_Password *lm_history;		struct ldb_val supplemental;		NTTIME last_set;		uint32_t kvno;	} g;};static int setup_nt_fields(struct setup_password_fields_io *io){	uint32_t i;	io->g.nt_hash = io->n.nt_hash;	if (io->domain->pwdHistoryLength == 0) {		return LDB_SUCCESS;	}	/* We might not have an old NT password */	io->g.nt_history = talloc_array(io->ac,					struct samr_Password,					io->domain->pwdHistoryLength);	if (!io->g.nt_history) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {		io->g.nt_history[i+1] = io->o.nt_history[i];	}	io->g.nt_history_len = i + 1;	if (io->g.nt_hash) {		io->g.nt_history[0] = *io->g.nt_hash;	} else {		/* 		 * TODO: is this correct?		 * the simular behavior is correct for the lm history case		 */		E_md4hash("", io->g.nt_history[0].hash);	}	return LDB_SUCCESS;}static int setup_lm_fields(struct setup_password_fields_io *io){	uint32_t i;	io->g.lm_hash = io->n.lm_hash;	if (io->domain->pwdHistoryLength == 0) {		return LDB_SUCCESS;	}	/* We might not have an old NT password */	io->g.lm_history = talloc_array(io->ac,					struct samr_Password,					io->domain->pwdHistoryLength);	if (!io->g.lm_history) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {		io->g.lm_history[i+1] = io->o.lm_history[i];	}	io->g.lm_history_len = i + 1;	if (io->g.lm_hash) {		io->g.lm_history[0] = *io->g.lm_hash;	} else {		E_deshash("", io->g.lm_history[0].hash);	}	return LDB_SUCCESS;}static int setup_primary_kerberos(struct setup_password_fields_io *io,				  const struct supplementalCredentialsBlob *old_scb,				  struct package_PrimaryKerberosBlob *pkb){	krb5_error_code krb5_ret;	Principal *salt_principal;	krb5_salt salt;	krb5_keyblock key;	uint32_t k=0;	struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;	struct supplementalCredentialsPackage *old_scp = NULL;	struct package_PrimaryKerberosBlob _old_pkb;	struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;	uint32_t i;	enum ndr_err_code ndr_err;	/* Many, many thanks to lukeh@padl.com for this	 * algorithm, described in his Nov 10 2004 mail to	 * samba-technical@samba.org */	/*	 * Determine a salting principal	 */	if (io->u.is_computer) {		char *name;		char *saltbody;		name = talloc_strdup(io->ac, io->u.sAMAccountName);		if (!name) {			ldb_oom(io->ac->module->ldb);			return LDB_ERR_OPERATIONS_ERROR;		}		if (name[strlen(name)-1] == '$') {			name[strlen(name)-1] = '\0';		}		saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);		if (!saltbody) {			ldb_oom(io->ac->module->ldb);			return LDB_ERR_OPERATIONS_ERROR;		}				krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,					       &salt_principal,					       io->domain->realm, "host",					       saltbody, NULL);	} else if (io->u.user_principal_name) {		char *user_principal_name;		char *p;		user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);		if (!user_principal_name) {			ldb_oom(io->ac->module->ldb);			return LDB_ERR_OPERATIONS_ERROR;		}		p = strchr(user_principal_name, '@');		if (p) {			p[0] = '\0';		}		krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,					       &salt_principal,					       io->domain->realm, user_principal_name,					       NULL);	} else {		krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,					       &salt_principal,					       io->domain->realm, io->u.sAMAccountName,					       NULL);	}	if (krb5_ret) {		ldb_asprintf_errstring(io->ac->module->ldb,				       "setup_primary_kerberos: "				       "generation of a salting principal failed: %s",				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));		return LDB_ERR_OPERATIONS_ERROR;	}	/*	 * create salt from salt_principal	 */	krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,				    salt_principal, &salt);	krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);	if (krb5_ret) {		ldb_asprintf_errstring(io->ac->module->ldb,				       "setup_primary_kerberos: "				       "generation of krb5_salt failed: %s",				       smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));		return LDB_ERR_OPERATIONS_ERROR;	}	/* create a talloc copy */	pkb3->salt.string = talloc_strndup(io->ac,					  salt.saltvalue.data,					  salt.saltvalue.length);	krb5_free_salt(io->smb_krb5_context->krb5_context, salt);	if (!pkb3->salt.string) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	salt.saltvalue.data	= discard_const(pkb3->salt.string);	salt.saltvalue.length	= strlen(pkb3->salt.string);	/*	 * prepare generation of keys	 *	 * ENCTYPE_AES256_CTS_HMAC_SHA1_96 (disabled by default)	 * ENCTYPE_DES_CBC_MD5	 * ENCTYPE_DES_CBC_CRC	 *	 * NOTE: update num_keys when you add another enctype!	 */	pkb3->num_keys	= 3;	pkb3->keys	= talloc_array(io->ac, struct package_PrimaryKerberosKey, pkb3->num_keys);	if (!pkb3->keys) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	pkb3->unknown3	= talloc_zero_array(io->ac, uint64_t, pkb3->num_keys);	if (!pkb3->unknown3) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	if (lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"), NULL, "password_hash", "create_aes_key", false)) {	/*	 * TODO:	 *	 * w2k and w2k3 doesn't support AES, so we'll not include	 * the AES key here yet.	 *	 * Also we don't have an example supplementalCredentials blob	 * from Windows Longhorn Server with AES support	 *	 */	/*	 * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of	 * the salt and the cleartext password	 */	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,					   ENCTYPE_AES256_CTS_HMAC_SHA1_96,					   io->n.cleartext,					   salt,					   &key);	pkb3->keys[k].keytype	= ENCTYPE_AES256_CTS_HMAC_SHA1_96;	pkb3->keys[k].value	= talloc(pkb3->keys, DATA_BLOB);	if (!pkb3->keys[k].value) {		krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	*pkb3->keys[k].value	= data_blob_talloc(pkb3->keys[k].value,						   key.keyvalue.data,						   key.keyvalue.length);	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);	if (!pkb3->keys[k].value->data) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	k++;}	/*	 * create ENCTYPE_DES_CBC_MD5 key out of	 * the salt and the cleartext password	 */	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,					   ENCTYPE_DES_CBC_MD5,					   io->n.cleartext,					   salt,					   &key);	pkb3->keys[k].keytype	= ENCTYPE_DES_CBC_MD5;	pkb3->keys[k].value	= talloc(pkb3->keys, DATA_BLOB);	if (!pkb3->keys[k].value) {		krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	*pkb3->keys[k].value	= data_blob_talloc(pkb3->keys[k].value,						   key.keyvalue.data,						   key.keyvalue.length);	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);	if (!pkb3->keys[k].value->data) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	k++;	/*	 * create ENCTYPE_DES_CBC_CRC key out of	 * the salt and the cleartext password	 */	krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,					   ENCTYPE_DES_CBC_CRC,					   io->n.cleartext,					   salt,					   &key);	pkb3->keys[k].keytype	= ENCTYPE_DES_CBC_CRC;	pkb3->keys[k].value	= talloc(pkb3->keys, DATA_BLOB);	if (!pkb3->keys[k].value) {		krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	*pkb3->keys[k].value	= data_blob_talloc(pkb3->keys[k].value,						   key.keyvalue.data,						   key.keyvalue.length);	krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);	if (!pkb3->keys[k].value->data) {		ldb_oom(io->ac->module->ldb);		return LDB_ERR_OPERATIONS_ERROR;	}	k++;	/* fix up key number */	pkb3->num_keys = k;	/* initialize the old keys to zero */	pkb3->num_old_keys	= 0;	pkb3->old_keys		= NULL;	pkb3->unknown3_old	= NULL;	/* if there're no old keys, then we're done */	if (!old_scb) {		return LDB_SUCCESS;	}	for (i=0; i < old_scb->sub.num_packages; i++) {		if (old_scb->sub.packages[i].unknown1 != 0x00000001) {			continue;		}		if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {			continue;		}		if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {			continue;		}		old_scp = &old_scb->sub.packages[i];		break;	}	/* Primary:Kerberos element of supplementalCredentials */	if (old_scp) {		DATA_BLOB blob;		blob = strhex_to_data_blob(old_scp->data);		if (!blob.data) {			ldb_oom(io->ac->module->ldb);			return LDB_ERR_OPERATIONS_ERROR;		}		talloc_steal(io->ac, blob.data);		/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */		ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_pkb,					       (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {			NTSTATUS status = ndr_map_error2ntstatus(ndr_err);			ldb_asprintf_errstring(io->ac->module->ldb,					       "setup_primary_kerberos: "					       "failed to pull old package_PrimaryKerberosBlob: %s",					       nt_errstr(status));			return LDB_ERR_OPERATIONS_ERROR;		}		if (_old_pkb.version != 3) {			ldb_asprintf_errstring(io->ac->module->ldb,					       "setup_primary_kerberos: "					       "package_PrimaryKerberosBlob version[%u] expected[3]",					       _old_pkb.version);			return LDB_ERR_OPERATIONS_ERROR;		}		old_pkb3 = &_old_pkb.ctr.ctr3;	}	/* if we didn't found the old keys we're done */	if (!old_pkb3) {		return LDB_SUCCESS;	}	/* fill in the old keys */	pkb3->num_old_keys	= old_pkb3->num_keys;	pkb3->old_keys		= old_pkb3->keys;	pkb3->unknown3_old	= old_pkb3->unknown3;	return LDB_SUCCESS;}static int setup_primary_wdigest(struct setup_password_fields_io *io,				 const struct supplementalCredentialsBlob *old_scb,				 struct package_PrimaryWDigestBlob *pdb){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -