Esempio n. 1
0
/*
  fill in the cldap netlogon union for a given version
*/
static NTSTATUS cldapd_netlogon_fill(struct cldapd_server *cldapd,
				     TALLOC_CTX *mem_ctx,
				     const char *domain,
				     const char *domain_guid,
				     const char *user,
				     const char *src_address,
				     uint32_t version,
				     union nbt_cldap_netlogon *netlogon)
{
	const char *ref_attrs[] = {"nETBIOSName", "dnsRoot", "ncName", NULL};
	const char *dom_attrs[] = {"objectGUID", NULL};
	struct ldb_message **ref_res, **dom_res;
	int ret, count = 0;
	const char **services = lp_server_services();
	uint32_t server_type;
	const char *pdc_name;
	struct GUID domain_uuid;
	const char *realm;
	const char *dns_domain;
	const char *pdc_dns_name;
	const char *flatname;
	const char *server_site;
	const char *client_site;
	const char *pdc_ip;
	struct ldb_dn *partitions_basedn;

	partitions_basedn = samdb_partitions_dn(cldapd->samctx, mem_ctx);

	/* the domain has an optional trailing . */
	if (domain && domain[strlen(domain)-1] == '.') {
		domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1);
	}

	if (domain) {
		struct ldb_result *dom_ldb_result;
		struct ldb_dn *dom_dn;
		/* try and find the domain */
		count = gendb_search(cldapd->samctx, mem_ctx, partitions_basedn, &ref_res, ref_attrs, 
				   "(&(&(objectClass=crossRef)(dnsRoot=%s))(nETBIOSName=*))", 
				   domain);
		if (count == 1) {
			dom_dn = samdb_result_dn(cldapd->samctx, mem_ctx, ref_res[0], "ncName", NULL);
			if (!dom_dn) {
				return NT_STATUS_NO_SUCH_DOMAIN;
			}
			ret = ldb_search(cldapd->samctx, dom_dn,
					 LDB_SCOPE_BASE, "objectClass=domain", 
					 dom_attrs, &dom_ldb_result);
			if (ret != LDB_SUCCESS) {
				DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain, ldb_dn_get_linearized(dom_dn), ldb_errstring(cldapd->samctx)));
				return NT_STATUS_NO_SUCH_DOMAIN;
			}
			talloc_steal(mem_ctx, dom_ldb_result);
			if (dom_ldb_result->count != 1) {
				DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain, ldb_dn_get_linearized(dom_dn)));
				return NT_STATUS_NO_SUCH_DOMAIN;
			}
			dom_res = dom_ldb_result->msgs;
		}
	}

	if (count == 0 && domain_guid) {
		/* OK, so no dice with the name, try and find the domain with the GUID */
		count = gendb_search(cldapd->samctx, mem_ctx, NULL, &dom_res, dom_attrs, 
				   "(&(objectClass=domainDNS)(objectGUID=%s))", 
				   domain_guid);
		if (count == 1) {
			/* try and find the domain */
			ret = gendb_search(cldapd->samctx, mem_ctx, partitions_basedn, &ref_res, ref_attrs, 
					   "(&(objectClass=crossRef)(ncName=%s))", 
					   ldb_dn_get_linearized(dom_res[0]->dn));
			if (ret != 1) {
				DEBUG(2,("Unable to find referece to '%s' in sam\n",
					 ldb_dn_get_linearized(dom_res[0]->dn)));
				return NT_STATUS_NO_SUCH_DOMAIN;
			}
		}
	}

	if (count == 0) {
		DEBUG(2,("Unable to find domain with name %s or GUID {%s}\n", domain, domain_guid));
		return NT_STATUS_NO_SUCH_DOMAIN;
	}

	server_type      = 
		NBT_SERVER_PDC | NBT_SERVER_GC | 
		NBT_SERVER_DS | NBT_SERVER_TIMESERV |
		NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE | 
		NBT_SERVER_GOOD_TIMESERV;

	if (str_list_check(services, "ldap")) {
		server_type |= NBT_SERVER_LDAP;
	}

	if (str_list_check(services, "kdc")) {
		server_type |= NBT_SERVER_KDC;
	}

	pdc_name         = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name());
	domain_uuid      = samdb_result_guid(dom_res[0], "objectGUID");
	realm            = samdb_result_string(ref_res[0], "dnsRoot", lp_realm());
	dns_domain       = samdb_result_string(ref_res[0], "dnsRoot", lp_realm());
	pdc_dns_name     = talloc_asprintf(mem_ctx, "%s.%s", 
					   strlower_talloc(mem_ctx, lp_netbios_name()), 
					   dns_domain);

	flatname         = samdb_result_string(ref_res[0], "nETBIOSName", lp_workgroup());
	server_site      = "Default-First-Site-Name";
	client_site      = "Default-First-Site-Name";
	pdc_ip           = iface_best_ip(src_address);

	ZERO_STRUCTP(netlogon);

	switch (version & 0xF) {
	case 0:
	case 1:
		netlogon->logon1.type        = (user?19+2:19);
		netlogon->logon1.pdc_name    = pdc_name;
		netlogon->logon1.user_name   = user;
		netlogon->logon1.domain_name = flatname;
		netlogon->logon1.nt_version  = 1;
		netlogon->logon1.lmnt_token  = 0xFFFF;
		netlogon->logon1.lm20_token  = 0xFFFF;
		break;
	case 2:
	case 3:
		netlogon->logon3.type         = (user?19+2:19);
		netlogon->logon3.pdc_name     = pdc_name;
		netlogon->logon3.user_name    = user;
		netlogon->logon3.domain_name  = flatname;
		netlogon->logon3.domain_uuid  = domain_uuid;
		netlogon->logon3.forest       = realm;
		netlogon->logon3.dns_domain   = dns_domain;
		netlogon->logon3.pdc_dns_name = pdc_dns_name;
		netlogon->logon3.pdc_ip       = pdc_ip;
		netlogon->logon3.server_type  = server_type;
		netlogon->logon3.lmnt_token   = 0xFFFF;
		netlogon->logon3.lm20_token   = 0xFFFF;
		break;
	case 4:
	case 5:
	case 6:
	case 7:
		netlogon->logon5.type         = (user?23+2:23);
		netlogon->logon5.server_type  = server_type;
		netlogon->logon5.domain_uuid  = domain_uuid;
		netlogon->logon5.forest       = realm;
		netlogon->logon5.dns_domain   = dns_domain;
		netlogon->logon5.pdc_dns_name = pdc_dns_name;
		netlogon->logon5.domain       = flatname;
		netlogon->logon5.pdc_name     = lp_netbios_name();
		netlogon->logon5.user_name    = user;
		netlogon->logon5.server_site  = server_site;
		netlogon->logon5.client_site  = client_site;
		netlogon->logon5.lmnt_token   = 0xFFFF;
		netlogon->logon5.lm20_token   = 0xFFFF;
		break;
	default:
		netlogon->logon13.type         = (user?23+2:23);
		netlogon->logon13.server_type  = server_type;
		netlogon->logon13.domain_uuid  = domain_uuid;
		netlogon->logon13.forest       = realm;
		netlogon->logon13.dns_domain   = dns_domain;
		netlogon->logon13.pdc_dns_name = pdc_dns_name;
		netlogon->logon13.domain       = flatname;
		netlogon->logon13.pdc_name     = lp_netbios_name();
		netlogon->logon13.user_name    = user;
		netlogon->logon13.server_site  = server_site;
		netlogon->logon13.client_site  = client_site;
		netlogon->logon13.unknown      = 10;
		netlogon->logon13.unknown2     = 2;
		netlogon->logon13.pdc_ip       = pdc_ip;
		netlogon->logon13.lmnt_token   = 0xFFFF;
		netlogon->logon13.lm20_token   = 0xFFFF;
		break;
	}

	return NT_STATUS_OK;
}
Esempio n. 2
0
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)
{
    int ldb_ret;
    struct ldb_result *domain_res = NULL;
    const char * const *domain_attrs;
    const char * const *result_attrs;
    struct ldb_message **result_res = NULL;
    struct ldb_message *result = NULL;
    struct ldb_dn *result_basedn = NULL;
    int i;
    char *p;
    struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);

    const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_null[] = { NULL };

    const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_canonical[] = { "canonicalName", NULL };

    const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
    const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};

    const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_guid[] = { "objectGUID", NULL};

    const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};

    const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
    const char * const _result_attrs_none[] = { NULL};

    /* here we need to set the attrs lists for domain and result lookups */
    switch (format_desired) {
    case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
        domain_attrs = _domain_attrs_1779;
        result_attrs = _result_attrs_null;
        break;
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
        domain_attrs = _domain_attrs_canonical;
        result_attrs = _result_attrs_canonical;
        break;
    case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
        domain_attrs = _domain_attrs_nt4;
        result_attrs = _result_attrs_nt4;
        break;
    case DRSUAPI_DS_NAME_FORMAT_GUID:
        domain_attrs = _domain_attrs_guid;
        result_attrs = _result_attrs_guid;
        break;
    case DRSUAPI_DS_NAME_FORMAT_DISPLAY:
        domain_attrs = _domain_attrs_display;
        result_attrs = _result_attrs_display;
        break;
    default:
        domain_attrs = _domain_attrs_none;
        result_attrs = _result_attrs_none;
        break;
    }

    if (domain_filter) {
        /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
        ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
                             partitions_basedn,
                             LDB_SCOPE_ONELEVEL,
                             domain_attrs,
                             "%s", domain_filter);

        if (ldb_ret != LDB_SUCCESS) {
            DEBUG(2, ("DsCrackNameOneFilter 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:
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        default:
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
            return WERR_OK;
        }

        info1->dns_domain_name	= samdb_result_string(domain_res->msgs[0], "dnsRoot", NULL);
        W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
        info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
    } else {
        info1->dns_domain_name	= NULL;
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    }

    if (result_filter) {
        int ret;
        struct ldb_result *res;
        if (domain_res) {
            result_basedn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);

            ret = ldb_search(sam_ctx, mem_ctx, &res,
                             result_basedn, LDB_SCOPE_SUBTREE,
                             result_attrs, "%s", result_filter);
            if (ret != LDB_SUCCESS) {
                talloc_free(result_res);
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            ldb_ret = res->count;
            result_res = res->msgs;
        } else {
            /* search with the 'phantom root' flag */
            struct ldb_request *req;

            res = talloc_zero(mem_ctx, struct ldb_result);
            W_ERROR_HAVE_NO_MEMORY(res);

            ret = ldb_build_search_req(&req, sam_ctx, mem_ctx,
                                       ldb_get_root_basedn(sam_ctx),
                                       LDB_SCOPE_SUBTREE,
                                       result_filter,
                                       result_attrs,
                                       NULL,
                                       res,
                                       ldb_search_default_callback,
                                       NULL);
            if (ret == LDB_SUCCESS) {
                struct ldb_search_options_control *search_options;
                search_options = talloc(req, struct ldb_search_options_control);
                W_ERROR_HAVE_NO_MEMORY(search_options);
                search_options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;

                ret = ldb_request_add_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID, false, search_options);
            }
            if (ret != LDB_SUCCESS) {
                talloc_free(res);
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }

            ret = ldb_request(sam_ctx, req);

            if (ret == LDB_SUCCESS) {
                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
            }

            talloc_free(req);

            if (ret != LDB_SUCCESS) {
                DEBUG(2, ("DsCrackNameOneFilter phantom root search failed: %s",
                          ldb_errstring(sam_ctx)));
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            ldb_ret = res->count;
            result_res = res->msgs;
        }
    } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
/*
 * This function will workout the filtering parameter in order to be able to do
 * the adapted search when the incomming format is format_functional.
 * This boils down to defining the search_dn (passed as pointer to ldb_dn *) and the
 * ldap filter request.
 * Main input parameters are:
 * * name, which is the portion of the functional name after the
 * first '/'.
 * * domain_filter, which is a ldap search filter used to find the NC DN given the
 * function name to crack.
 */
static WERROR get_format_functional_filtering_param(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
			char *name, struct drsuapi_DsNameInfo1 *info1,
			struct ldb_dn **psearch_dn, const char *domain_filter, const char **presult_filter)
{
	struct ldb_result *domain_res = NULL;
	const char * const domain_attrs[] = {"ncName", NULL};
	struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
	int ldb_ret;
	char *account,  *s, *result_filter = NULL;
	struct ldb_dn *search_dn = NULL;

	*psearch_dn = NULL;
	*presult_filter = NULL;

	ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
				partitions_basedn,
				LDB_SCOPE_ONELEVEL,
				domain_attrs,
				"%s", domain_filter);

	if (ldb_ret != LDB_SUCCESS) {
		DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_FOOBAR;
	}

	if (domain_res->count == 1) {
		struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
		const char * const name_attrs[] = {"name", NULL};

		account = name;
		s = strchr(account, '/');
		talloc_free(domain_res);
		while(s) {
			s[0] = '\0';
			s++;

			ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
						tmp_dn,
						LDB_SCOPE_ONELEVEL,
						name_attrs,
						"name=%s", account);

			if (ldb_ret != LDB_SUCCESS) {
				DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
				info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
				return WERR_OK;
			}
			talloc_free(tmp_dn);
			switch (domain_res->count) {
			case 1:
				break;
			case 0:
				talloc_free(domain_res);
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
				return WERR_OK;
			default:
				talloc_free(domain_res);
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
				return WERR_OK;
			}

			tmp_dn = talloc_steal(mem_ctx, domain_res->msgs[0]->dn);
			talloc_free(domain_res);
			search_dn = tmp_dn;
			account = s;
			s = strchr(account, '/');
		}
		account = ldb_binary_encode_string(mem_ctx, account);
		W_ERROR_HAVE_NO_MEMORY(account);
		result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
						account);
		W_ERROR_HAVE_NO_MEMORY(result_filter);
	}
	*psearch_dn = search_dn;
	*presult_filter = result_filter;
	return WERR_OK;
}
static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
				   struct smb_krb5_context *smb_krb5_context,
				   uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
				   enum drsuapi_DsNameFormat format_desired,
				   struct ldb_dn *name_dn, const char *name, 
				   const char *domain_filter, const char *result_filter, 
				   struct drsuapi_DsNameInfo1 *info1,
				   int scope, struct ldb_dn *search_dn)
{
	int ldb_ret;
	struct ldb_result *domain_res = NULL;
	const char * const *domain_attrs;
	const char * const *result_attrs;
	struct ldb_message **result_res = NULL;
	struct ldb_message *result = NULL;
	int i;
	char *p;
	struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);

	const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_null[] = { NULL };

	const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_canonical[] = { "canonicalName", NULL };

	const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
	const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};

	const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_guid[] = { "objectGUID", NULL};

	const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};

	const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
	const char * const _result_attrs_none[] = { NULL};

	/* here we need to set the attrs lists for domain and result lookups */
	switch (format_desired) {
	case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
		domain_attrs = _domain_attrs_1779;
		result_attrs = _result_attrs_null;
		break;
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
		domain_attrs = _domain_attrs_canonical;
		result_attrs = _result_attrs_canonical;
		break;
	case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
		domain_attrs = _domain_attrs_nt4;
		result_attrs = _result_attrs_nt4;
		break;
	case DRSUAPI_DS_NAME_FORMAT_GUID:		
		domain_attrs = _domain_attrs_guid;
		result_attrs = _result_attrs_guid;
		break;
	case DRSUAPI_DS_NAME_FORMAT_DISPLAY:		
		domain_attrs = _domain_attrs_display;
		result_attrs = _result_attrs_display;
		break;
	default:
		domain_attrs = _domain_attrs_none;
		result_attrs = _result_attrs_none;
		break;
	}

	if (domain_filter) {
		/* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
		ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
					     partitions_basedn,
					     LDB_SCOPE_ONELEVEL,
					     domain_attrs,
					     "%s", domain_filter);

		if (ldb_ret != LDB_SUCCESS) {
			DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
			info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
			return WERR_OK;
		}

		switch (domain_res->count) {
		case 1:
			break;
		case 0:
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
			return WERR_OK;
		default:
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
			return WERR_OK;
		}

		info1->dns_domain_name	= ldb_msg_find_attr_as_string(domain_res->msgs[0], "dnsRoot", NULL);
		W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
		info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
	} else {
		info1->dns_domain_name	= NULL;
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
	}

	if (result_filter) {
		int ret;
		struct ldb_result *res;
		uint32_t dsdb_flags = 0;
		struct ldb_dn *real_search_dn = NULL;
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;

		/*
		 * From 4.1.4.2.11 of MS-DRSR
		 * if DS_NAME_FLAG_GCVERIFY in flags then
		 * rt := select all O from all
		 * where attrValue in GetAttrVals(O, att, false)
		 * else
		 * rt := select all O from subtree DefaultNC()
		 * where attrValue in GetAttrVals(O, att, false)
		 * endif
		 * return rt
		 */
		if (format_flags & DRSUAPI_DS_NAME_FLAG_GCVERIFY ||
		    format_offered == DRSUAPI_DS_NAME_FORMAT_GUID)
		{
			dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
		} else if (domain_res) {
			if (!search_dn) {
				struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
				real_search_dn = tmp_dn;
			} else {
				real_search_dn = search_dn;
			}
		} else {
			real_search_dn = ldb_get_default_basedn(sam_ctx);
		}
		if (format_desired == DRSUAPI_DS_NAME_FORMAT_GUID){
			 dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
		}
		/* search with the 'phantom root' flag */
		ret = dsdb_search(sam_ctx, mem_ctx, &res,
				  real_search_dn,
				  scope,
				  result_attrs,
				  dsdb_flags,
				  "%s", result_filter);
		if (ret != LDB_SUCCESS) {
			DEBUG(2, ("DsCrackNameOneFilter search from '%s' with flags 0x%08x failed: %s\n",
				  ldb_dn_get_linearized(real_search_dn),
				  dsdb_flags,
				  ldb_errstring(sam_ctx)));
			info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
			return WERR_OK;
		}

		ldb_ret = res->count;
		result_res = res->msgs;
	} else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
		ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
					  result_attrs);
	} else if (domain_res) {
		name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
		ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
					  result_attrs);
	} else {
		/* Can't happen */
		DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n"));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_OK;
	}

	switch (ldb_ret) {
	case 1:
		result = result_res[0];
		break;
	case 0:
		switch (format_offered) {
		case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: 
			return DsCrackNameSPNAlias(sam_ctx, mem_ctx, 
						   smb_krb5_context, 
						   format_flags, format_offered, format_desired,
						   name, info1);

		case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
			return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, 
					      format_flags, format_offered, format_desired,
					      name, info1);
		default:
			break;
		}
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		return WERR_OK;
	case -1:
		DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx)));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_OK;
	default:
		switch (format_offered) {
		case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
		case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
		{
			const char *canonical_name = NULL; /* Not required, but we get warnings... */
			/* We may need to manually filter further */
			for (i = 0; i < ldb_ret; i++) {
				switch (format_offered) {
				case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
					canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn);
					break;
				case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
					canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn);
					break;
				default:
					break;
				}
				if (strcasecmp_m(canonical_name, name) == 0) {
					result = result_res[i];
					break;
				}
			}
			if (!result) {
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
				return WERR_OK;
			}
		}
		/* FALL TROUGH */
		default:
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
			return WERR_OK;
		}
	}

	info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn);
	W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
	p = strchr(info1->dns_domain_name, '/');
	if (p) {
		p[0] = '\0';
	}

	/* here we can use result and domain_res[0] */
	switch (format_desired) {
	case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
		info1->result_name	= ldb_dn_alloc_linearized(mem_ctx, result->dn);
		W_ERROR_HAVE_NO_MEMORY(info1->result_name);

		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
		info1->result_name	= ldb_msg_find_attr_as_string(result, "canonicalName", NULL);
		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
		/* Not in the virtual ldb attribute */
		return DsCrackNameOneSyntactical(mem_ctx, 
						 DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
						 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
						 result->dn, name, info1);
	}
	case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {

		const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
		const char *_acc = "", *_dom = "";
		if (sid == NULL) {
			info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
			return WERR_OK;
		}

		if (samdb_find_attribute(sam_ctx, result, "objectClass",
					 "domain")) {
			/* This can also find a DomainDNSZones entry,
			 * but it won't have the SID we just
			 * checked.  */
			ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
						     partitions_basedn,
						     LDB_SCOPE_ONELEVEL,
						     domain_attrs,
						     "(ncName=%s)", ldb_dn_get_linearized(result->dn));

			if (ldb_ret != LDB_SUCCESS) {
				DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
				info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
				return WERR_OK;
			}

			switch (domain_res->count) {
			case 1:
				break;
			case 0:
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
				return WERR_OK;
			default:
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
				return WERR_OK;
			}
			_dom = ldb_msg_find_attr_as_string(domain_res->msgs[0], "nETBIOSName", NULL);
			W_ERROR_HAVE_NO_MEMORY(_dom);
		} else {
			_acc = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
			if (!_acc) {
				info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
				return WERR_OK;
			}
			if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx, SID_BUILTIN), sid)) {
				_dom = "BUILTIN";
			} else {
				const char *attrs[] = { NULL };
				struct ldb_result *domain_res2;
				struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
				if (!dom_sid) {
					return WERR_OK;
				}
				dom_sid->num_auths--;
				ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
							     NULL,
							     LDB_SCOPE_BASE,
							     attrs,
							     "(&(objectSid=%s)(objectClass=domain))", 
							     ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));

				if (ldb_ret != LDB_SUCCESS) {
					DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx)));
					info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
					return WERR_OK;
				}

				switch (domain_res->count) {
				case 1:
					break;
				case 0:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
					return WERR_OK;
				default:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
					return WERR_OK;
				}

				ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2,
							     partitions_basedn,
							     LDB_SCOPE_ONELEVEL,
							     domain_attrs,
							     "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));

				if (ldb_ret != LDB_SUCCESS) {
					DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
					info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
					return WERR_OK;
				}

				switch (domain_res2->count) {
				case 1:
					break;
				case 0:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
					return WERR_OK;
				default:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
					return WERR_OK;
				}
				_dom = ldb_msg_find_attr_as_string(domain_res2->msgs[0], "nETBIOSName", NULL);
				W_ERROR_HAVE_NO_MEMORY(_dom);
			}
		}

		info1->result_name	= talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
		W_ERROR_HAVE_NO_MEMORY(info1->result_name);

		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_GUID: {
		struct GUID guid;

		guid = samdb_result_guid(result, "objectGUID");

		info1->result_name	= GUID_string2(mem_ctx, &guid);
		W_ERROR_HAVE_NO_MEMORY(info1->result_name);

		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
		info1->result_name	= ldb_msg_find_attr_as_string(result, "displayName", NULL);
		if (!info1->result_name) {
			info1->result_name	= ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
		} 
		if (!info1->result_name) {
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		} else {
			info1->status = DRSUAPI_DS_NAME_STATUS_OK;
		}
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN:	
	case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
		info1->dns_domain_name = NULL;
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_OK;
	}
	default:
		info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
		return WERR_OK;
	}
}
Esempio n. 5
0
/*
  add special SPNs needed for DRS replication to machine accounts when
  an AddEntry is done to create a nTDSDSA object
 */
static WERROR drsuapi_add_SPNs(struct drsuapi_bind_state *b_state,
			       struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
			       const struct drsuapi_DsReplicaObjectListItem *first_object)
{
	int ret;
	const struct drsuapi_DsReplicaObjectListItem *obj;
	const char *attrs[] = { "serverReference", "objectGUID", NULL };

	for (obj = first_object; obj; obj=obj->next_object) {
		const char *dn_string = obj->object.identifier->dn;
		struct ldb_dn *dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, dn_string);
		struct ldb_result *res, *res2;
		struct ldb_dn *ref_dn;
		struct GUID ntds_guid;
		struct ldb_message *msg;
		struct ldb_message_element *el;
		const char *ntds_guid_str;
		const char *dom_string;
		const char *attrs2[] = { "dNSHostName", "cn", NULL };
		const char *dNSHostName, *cn;

		DEBUG(6,(__location__ ": Adding SPNs for %s\n", 
			 ldb_dn_get_linearized(dn)));
		 
		ret = ldb_search(b_state->sam_ctx, mem_ctx, &res,
				 dn, LDB_SCOPE_BASE, attrs,
				 "(objectClass=ntDSDSA)");
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed to find dn '%s'\n", dn_string));
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		if (res->count < 1) {
			/* we only add SPNs for nTDSDSA objects */
			continue;
		}

		ref_dn = samdb_result_dn(b_state->sam_ctx, mem_ctx, res->msgs[0], "serverReference", NULL);
		if (ref_dn == NULL) {
			/* we only add SPNs for objects with a
			   serverReference */
			continue;
		}

		DEBUG(6,(__location__ ": serverReference %s\n", 
			 ldb_dn_get_linearized(ref_dn)));

		ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");

		ntds_guid_str = GUID_string(res, &ntds_guid);

		dom_string = lpcfg_dnsdomain(dce_call->conn->dce_ctx->lp_ctx);

		/* get the dNSHostName and cn */
		ret = ldb_search(b_state->sam_ctx, mem_ctx, &res2,
				 ref_dn, LDB_SCOPE_BASE, attrs2, NULL);
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed to find ref_dn '%s'\n",
				 ldb_dn_get_linearized(ref_dn)));
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		dNSHostName = ldb_msg_find_attr_as_string(res2->msgs[0], "dNSHostName", NULL);
		cn = ldb_msg_find_attr_as_string(res2->msgs[0], "cn", NULL);

		/*
		 * construct a modify request to add the new SPNs to
		 * the machine account
		 */
		msg = ldb_msg_new(mem_ctx);
		if (msg == NULL) {
			return WERR_NOT_ENOUGH_MEMORY;
		}

		msg->dn = ref_dn;
		ret = ldb_msg_add_empty(msg, "servicePrincipalName",
					LDB_FLAG_MOD_ADD, &el);
		if (ret != LDB_SUCCESS) {
			return WERR_NOT_ENOUGH_MEMORY;
		}


		ldb_msg_add_steal_string(msg, "servicePrincipalName",
					 talloc_asprintf(el->values,
							 "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s",
							 ntds_guid_str, dom_string));
		ldb_msg_add_steal_string(msg, "servicePrincipalName",
					 talloc_asprintf(el->values, "ldap/%s._msdcs.%s",
							 ntds_guid_str, dom_string));
		if (cn) {
			ldb_msg_add_steal_string(msg, "servicePrincipalName",
						 talloc_asprintf(el->values, "ldap/%s", cn));
		}
		if (dNSHostName) {
			ldb_msg_add_steal_string(msg, "servicePrincipalName",
						 talloc_asprintf(el->values, "ldap/%s", dNSHostName));
		}
		if (el->num_values < 2) {
			return WERR_NOT_ENOUGH_MEMORY;
		}

		ret = dsdb_modify(b_state->sam_ctx, msg, DSDB_MODIFY_PERMISSIVE);
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed to add SPNs - %s\n",
				 ldb_errstring(b_state->sam_ctx)));
			return WERR_DS_DRA_INTERNAL_ERROR;
		}
	}
	
	return WERR_OK;
}