NTSTATUS register_gp_extension(TALLOC_CTX *gpext_ctx, int version, const char *name, const char *guid, struct gp_extension_methods *methods) { struct gp_extension_methods *test; struct gp_extension *entry; NTSTATUS status; if (!gpext_ctx) { return NT_STATUS_INTERNAL_DB_ERROR; } if ((version != SMB_GPEXT_INTERFACE_VERSION)) { DEBUG(0,("Failed to register gp extension.\n" "The module was compiled against " "SMB_GPEXT_INTERFACE_VERSION %d,\n" "current SMB_GPEXT_INTERFACE_VERSION is %d.\n" "Please recompile against the current " "version of samba!\n", version, SMB_GPEXT_INTERFACE_VERSION)); return NT_STATUS_OBJECT_TYPE_MISMATCH; } if (!guid || !name || !name[0] || !methods) { DEBUG(0,("Called with NULL pointer or empty name!\n")); return NT_STATUS_INVALID_PARAMETER; } test = get_methods_by_name(extensions, name); if (test) { DEBUG(0,("GP extension module %s already registered!\n", name)); return NT_STATUS_OBJECT_NAME_COLLISION; } entry = talloc_zero(gpext_ctx, struct gp_extension); NT_STATUS_HAVE_NO_MEMORY(entry); entry->name = talloc_strdup(gpext_ctx, name); NT_STATUS_HAVE_NO_MEMORY(entry->name); entry->guid = talloc_zero(gpext_ctx, struct GUID); NT_STATUS_HAVE_NO_MEMORY(entry->guid); status = GUID_from_string(guid, entry->guid); NT_STATUS_NOT_OK_RETURN(status); entry->methods = methods; DLIST_ADD(extensions, entry); DEBUG(2,("Successfully added GP extension '%s' %s\n", name, GUID_string2(gpext_ctx, entry->guid))); return NT_STATUS_OK; }
static bool test_guid_string2_valid(struct torture_context *tctx) { struct GUID g; g.time_low = 1; g.time_mid = 2; g.time_hi_and_version = 3; g.clock_seq[0] = 4; g.clock_seq[1] = 5; g.node[0] = 6; g.node[1] = 7; g.node[2] = 8; g.node[3] = 9; g.node[4] = 10; g.node[5] = 11; torture_assert_str_equal(tctx, "{00000001-0002-0003-0405-060708090a0b}", GUID_string2(tctx, &g), "parsing guid failed"); return true; }
.expected_str = talloc_asprintf(mem_ctx, "%s\n", dns_domain), .status = DRSUAPI_DS_NAME_STATUS_OK }, { .format_offered = DRSUAPI_DS_NAME_FORMAT_DISPLAY, .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779, .str = "CN=Microsoft Corporation,L=Redmond,S=Washington,C=US", .comment = "display name for Microsoft Support Account", .status = DRSUAPI_DS_NAME_STATUS_OK, .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE, .skip = torture_setting_bool(tctx, "samba4", false) }, { .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID, .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779, .str = GUID_string2(mem_ctx, torture_join_user_guid(priv->join)), .comment = "Account GUID -> DN", .expected_str = FQDN_1779_name, .status = DRSUAPI_DS_NAME_STATUS_OK }, { .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID, .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, .str = GUID_string2(mem_ctx, torture_join_user_guid(priv->join)), .comment = "Account GUID -> NT4 Account", .expected_str = talloc_asprintf(mem_ctx, "%s%s$", nt4_domain, test_dc), .status = DRSUAPI_DS_NAME_STATUS_OK }, { .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID, .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
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; } }
NTSTATUS gp_create_gpo (struct gp_context *gp_ctx, const char *display_name, struct gp_object **ret) { struct GUID guid_struct; char *guid_str; char *name; struct security_descriptor *sd; TALLOC_CTX *mem_ctx; struct gp_object *gpo; NTSTATUS status; /* Create a forked memory context, as a base for everything here */ mem_ctx = talloc_new(gp_ctx); NT_STATUS_HAVE_NO_MEMORY(mem_ctx); /* Create the gpo struct to return later */ gpo = talloc(gp_ctx, struct gp_object); if (gpo == NULL) { TALLOC_FREE(mem_ctx); return NT_STATUS_NO_MEMORY; } /* Generate a GUID */ guid_struct = GUID_random(); guid_str = GUID_string2(mem_ctx, &guid_struct); if (guid_str == NULL) { TALLOC_FREE(mem_ctx); return NT_STATUS_NO_MEMORY; } name = strupper_talloc(mem_ctx, guid_str); if (name == NULL) { TALLOC_FREE(mem_ctx); return NT_STATUS_NO_MEMORY; } /* Prepare the GPO struct */ gpo->dn = NULL; gpo->name = name; gpo->flags = 0; gpo->version = 0; gpo->display_name = talloc_strdup(gpo, display_name); if (gpo->display_name == NULL) { TALLOC_FREE(mem_ctx); return NT_STATUS_NO_MEMORY; } gpo->file_sys_path = talloc_asprintf(gpo, "\\\\%s\\sysvol\\%s\\Policies\\%s", lpcfg_dnsdomain(gp_ctx->lp_ctx), lpcfg_dnsdomain(gp_ctx->lp_ctx), name); if (gpo->file_sys_path == NULL) { TALLOC_FREE(mem_ctx); return NT_STATUS_NO_MEMORY; } /* Create the GPT */ status = gp_create_gpt(gp_ctx, name, gpo->file_sys_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to create GPT\n")); talloc_free(mem_ctx); return status; } /* Create the LDAP GPO, including CN=User and CN=Machine */ status = gp_create_ldap_gpo(gp_ctx, gpo); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to create LDAP group policy object\n")); talloc_free(mem_ctx); return status; } /* Get the new security descriptor */ status = gp_get_gpo_info(gp_ctx, gpo->dn, &gpo); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to fetch LDAP group policy object\n")); talloc_free(mem_ctx); return status; } /* Create matching file and DS security descriptors */ status = gp_create_gpt_security_descriptor(mem_ctx, gpo->security_descriptor, &sd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to convert ADS security descriptor to filesystem security descriptor\n")); talloc_free(mem_ctx); return status; } /* Set the security descriptor on the filesystem for this GPO */ status = gp_set_gpt_security_descriptor(gp_ctx, gpo, sd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to set security descriptor (ACL) on the file system\n")); talloc_free(mem_ctx); return status; } talloc_free(mem_ctx); *ret = gpo; return NT_STATUS_OK; }