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

📄 cracknames.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    Unix SMB/CIFS implementation.   endpoint server for the drsuapi pipe   DsCrackNames()   Copyright (C) Stefan Metzmacher 2004   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005      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/>.*/#include "includes.h"#include "librpc/gen_ndr/drsuapi.h"#include "rpc_server/common/common.h"#include "lib/ldb/include/ldb.h"#include "lib/ldb/include/ldb_errors.h"#include "system/kerberos.h"#include "auth/kerberos/kerberos.h"#include "libcli/ldap/ldap_ndr.h"#include "libcli/security/security.h"#include "librpc/gen_ndr/ndr_misc.h"#include "auth/auth.h"#include "util/util_ldb.h"#include "dsdb/samdb/samdb.h"#include "param/param.h"static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,				   struct smb_krb5_context *smb_krb5_context,				   uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,				   struct ldb_dn *name_dn, const char *name, 				   const char *domain_filter, const char *result_filter, 				   struct drsuapi_DsNameInfo1 *info1);static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx,					uint32_t format_offered, uint32_t format_desired,					struct ldb_dn *name_dn, const char *name, 					struct drsuapi_DsNameInfo1 *info1);static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, 					const char *name, 					struct drsuapi_DsNameInfo1 *info1) {	krb5_error_code ret;	krb5_principal principal;	/* perhaps it's a principal with a realm, so return the right 'domain only' response */	char **realm;	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 				    KRB5_PRINCIPAL_PARSE_MUST_REALM, &principal);	if (ret) {		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;		return WERR_OK;	}	/* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */	realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);		info1->dns_domain_name	= talloc_strdup(mem_ctx, *realm);	krb5_free_principal(smb_krb5_context->krb5_context, principal);		W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);		info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;	return WERR_OK;}		static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx, 						      TALLOC_CTX *mem_ctx,						      const char *alias_from,						      char **alias_to){	int i;	int ret;	struct ldb_result *res;	struct ldb_message_element *spnmappings;	TALLOC_CTX *tmp_ctx;	struct ldb_dn *service_dn;	char *service_dn_str;	const char *directory_attrs[] = {		"sPNMappings", 		NULL	};	tmp_ctx = talloc_new(mem_ctx);	if (!tmp_ctx) {		return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;	}	service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services");	if ( ! ldb_dn_add_base(service_dn, samdb_config_dn(ldb_ctx))) {		return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;	}	service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn);	if ( ! service_dn_str) {		return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;	}	ret = ldb_search(ldb_ctx, service_dn, LDB_SCOPE_BASE, "(objectClass=nTDSService)",			 directory_attrs, &res);	if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {		DEBUG(1, ("ldb_search: dn: %s not found: %s", service_dn_str, ldb_errstring(ldb_ctx)));		return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;	} else if (ret == LDB_ERR_NO_SUCH_OBJECT) {		DEBUG(1, ("ldb_search: dn: %s not found", service_dn_str));		return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;	} else if (res->count != 1) {		talloc_free(res);		DEBUG(1, ("ldb_search: dn: %s not found", service_dn_str));		return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;	}	talloc_steal(tmp_ctx, res);		spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");	if (!spnmappings || spnmappings->num_values == 0) {		DEBUG(1, ("ldb_search: dn: %s no sPNMappings attribute", service_dn_str));		talloc_free(tmp_ctx);		return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;	}	for (i = 0; i < spnmappings->num_values; i++) {		char *mapping, *p, *str;		mapping = talloc_strdup(tmp_ctx, 					(const char *)spnmappings->values[i].data);		if (!mapping) {			DEBUG(1, ("LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping\n", service_dn_str));			talloc_free(tmp_ctx);			return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;		}				/* C string manipulation sucks */				p = strchr(mapping, '=');		if (!p) {			DEBUG(1, ("ldb_search: dn: %s sPNMapping malformed: %s\n", 				  service_dn_str, mapping));			talloc_free(tmp_ctx);			return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;		}		p[0] = '\0';		p++;		do {			str = p;			p = strchr(p, ',');			if (p) {				p[0] = '\0';				p++;			}			if (strcasecmp(str, alias_from) == 0) {				*alias_to = mapping;				talloc_steal(mem_ctx, mapping);				talloc_free(tmp_ctx);				return DRSUAPI_DS_NAME_STATUS_OK;			}		} while (p);	}	DEBUG(4, ("LDB_lookup_spn_alias: no alias for service %s applicable\n", alias_from));	talloc_free(tmp_ctx);	return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;}/* When cracking a ServicePrincipalName, many services may be served * by the host/ servicePrincipalName.  The incoming query is for cifs/ * but we translate it here, and search on host/.  This is done after * the cifs/ entry has been searched for, making this a fallback */static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,				  struct smb_krb5_context *smb_krb5_context,				  uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,				  const char *name, struct drsuapi_DsNameInfo1 *info1){	WERROR wret;	krb5_error_code ret;	krb5_principal principal;	const char *service, *dns_name;	char *new_service;	char *new_princ;	enum drsuapi_DsNameStatus namestatus;		/* parse principal */	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 				    name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);	if (ret) {		DEBUG(2, ("Could not parse principal: %s: %s",			  name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 							   ret, mem_ctx)));		return WERR_NOMEM;	}		/* grab cifs/, http/ etc */		/* This is checked for in callers, but be safe */	if (principal->name.name_string.len < 2) {		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;		return WERR_OK;	}	service = principal->name.name_string.val[0];	dns_name = principal->name.name_string.val[1];		/* MAP it */	namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, 					  sam_ctx, mem_ctx, 					  service, &new_service);		if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {		info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;		info1->dns_domain_name	= talloc_strdup(mem_ctx, dns_name);		if (!info1->dns_domain_name) {			krb5_free_principal(smb_krb5_context->krb5_context, principal);			return WERR_NOMEM;		}		return WERR_OK;	} else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {		info1->status = namestatus;		krb5_free_principal(smb_krb5_context->krb5_context, principal);		return WERR_OK;	}		/* ooh, very nasty playing around in the Principal... */	free(principal->name.name_string.val[0]);	principal->name.name_string.val[0] = strdup(new_service);	if (!principal->name.name_string.val[0]) {		krb5_free_principal(smb_krb5_context->krb5_context, principal);		return WERR_NOMEM;	}		/* reform principal */	ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 				      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &new_princ);	if (ret) {		krb5_free_principal(smb_krb5_context->krb5_context, principal);		return WERR_NOMEM;	}		wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,				  new_princ, info1);	free(new_princ);	if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {		info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;		info1->dns_domain_name	= talloc_strdup(mem_ctx, dns_name);		if (!info1->dns_domain_name) {			wret = WERR_NOMEM;		}	}	krb5_free_principal(smb_krb5_context->krb5_context, principal);	return wret;}/* Subcase of CrackNames, for the userPrincipalName */static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,			     struct smb_krb5_context *smb_krb5_context,			     uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,			     const char *name, struct drsuapi_DsNameInfo1 *info1){	int ldb_ret;	WERROR status;	const char *domain_filter = NULL;	const char *result_filter = NULL;	krb5_error_code ret;	krb5_principal principal;	char **realm;	char *unparsed_name_short;	const char *domain_attrs[] = { NULL };	struct ldb_result *domain_res = NULL;		/* Prevent recursion */	if (!name) {		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;		return WERR_OK;	}	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 				    KRB5_PRINCIPAL_PARSE_MUST_REALM, &principal);	if (ret) {		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;		return WERR_OK;	}		realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal);	ldb_ret = ldb_search_exp_fmt(sam_ctx, mem_ctx, &domain_res, 				     samdb_partitions_dn(sam_ctx, mem_ctx), 				     LDB_SCOPE_ONELEVEL,				     domain_attrs,				     "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",				     ldb_binary_encode_string(mem_ctx, *realm), 				     ldb_binary_encode_string(mem_ctx, *realm));	if (ldb_ret != LDB_SUCCESS) {		DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx)));		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;		return WERR_OK;	}		switch (domain_res->count) {	case 1:		break;	case 0:		return dns_domain_from_principal(mem_ctx, smb_krb5_context, 						 name, info1);	default:		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;		return WERR_OK;	}		ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 				      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);	krb5_free_principal(smb_krb5_context->krb5_context, principal);			if (ret) {		free(unparsed_name_short);		return WERR_NOMEM;	}		/* This may need to be extended for more userPrincipalName variations */	result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", 					ldb_binary_encode_string(mem_ctx, unparsed_name_short));	domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));	if (!result_filter || !domain_filter) {		free(unparsed_name_short);		return WERR_NOMEM;	}	status = DsCrackNameOneFilter(sam_ctx, mem_ctx, 				      smb_krb5_context, 				      format_flags, format_offered, format_desired, 				      NULL, unparsed_name_short, domain_filter, result_filter, 				      info1);	free(unparsed_name_short);	return status;}/* Crack a single 'name', from format_offered into format_desired, returning the result in info1 */WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,			  uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,			  const char *name, struct drsuapi_DsNameInfo1 *info1){	krb5_error_code ret;	const char *domain_filter = NULL;	const char *result_filter = NULL;	struct ldb_dn *name_dn = NULL;	struct smb_krb5_context *smb_krb5_context;	ret = smb_krb5_init_context(mem_ctx, 				    (struct event_context *)ldb_get_opaque(sam_ctx, "EventContext"), 				    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), 				    &smb_krb5_context);					if (ret) {		return WERR_NOMEM;	}	info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;	info1->dns_domain_name = NULL;	info1->result_name = NULL;	if (!name) {		return WERR_INVALID_PARAM;	}	/* TODO: - fill the correct names in all cases!	 *       - handle format_flags	 */	/* here we need to set the domain_filter and/or the result_filter */	switch (format_offered) {	case DRSUAPI_DS_NAME_FORMAT_CANONICAL:	case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:	{		char *str, *s, *account;				if (strlen(name) == 0) {			info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;			return WERR_OK;		}				str = talloc_strdup(mem_ctx, name);		W_ERROR_HAVE_NO_MEMORY(str);				if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {			/* Look backwards for the \n, and replace it with / */			s = strrchr(str, '\n');			if (!s) {				info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;				return WERR_OK;			}			s[0] = '/';		}		s = strchr(str, '/');		if (!s) {			/* there must be at least one / */			info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;			return WERR_OK;		}				s[0] = '\0';		s++;		domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))", 						ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str)));		W_ERROR_HAVE_NO_MEMORY(domain_filter);		/* There may not be anything after the domain component (search for the domain itself) */		if (s[0]) {						account = strrchr(s, '/');			if (!account) {				account = s;			} else {				account++;			}			account = ldb_binary_encode_string(mem_ctx, account);			W_ERROR_HAVE_NO_MEMORY(account);

⌨️ 快捷键说明

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