diff options
Diffstat (limited to 'source4/rpc_server')
-rw-r--r-- | source4/rpc_server/config.mk | 1 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/addentry.c | 45 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 77 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/dcesrv_drsuapi.h | 2 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/getncchanges.c | 219 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/writespn.c | 145 |
6 files changed, 377 insertions, 112 deletions
diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk index 527770a8cd..5ff1bd5722 100644 --- a/source4/rpc_server/config.mk +++ b/source4/rpc_server/config.mk @@ -188,6 +188,7 @@ dcerpc_drsuapi_OBJ_FILES = $(rpc_serversrcdir)/drsuapi/dcesrv_drsuapi.o \ $(rpc_serversrcdir)/drsuapi/updaterefs.o \ $(rpc_serversrcdir)/drsuapi/getncchanges.o \ $(rpc_serversrcdir)/drsuapi/addentry.o \ + $(rpc_serversrcdir)/drsuapi/writespn.o \ $(rpc_serversrcdir)/drsuapi/drsutil.o ################################################ diff --git a/source4/rpc_server/drsuapi/addentry.c b/source4/rpc_server/drsuapi/addentry.c index ac94daa6a6..f63a96740f 100644 --- a/source4/rpc_server/drsuapi/addentry.c +++ b/source4/rpc_server/drsuapi/addentry.c @@ -43,13 +43,15 @@ static WERROR drsuapi_add_SPNs(struct drsuapi_bind_state *b_state, 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; + 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))); @@ -78,6 +80,18 @@ static WERROR drsuapi_add_SPNs(struct drsuapi_bind_state *b_state, dom_string = lp_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 @@ -94,20 +108,25 @@ static WERROR drsuapi_add_SPNs(struct drsuapi_bind_state *b_state, return WERR_NOMEM; } - el->num_values = 2; - el->values = talloc_array(msg->elements, struct ldb_val, 2); - if (el->values == NULL) { + + 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_NOMEM; } - /* the magic constant is the GUID of the DRSUAPI RPC - interface */ - el->values[0].data = (uint8_t *)talloc_asprintf(el->values, - "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s", - ntds_guid_str, dom_string); - el->values[0].length = strlen((char *)el->values[0].data); - el->values[1].data = (uint8_t *)talloc_asprintf(el->values, "ldap/%s._msdcs.%s", - ntds_guid_str, dom_string); - el->values[1].length = strlen((char *)el->values[1].data); ret = ldb_modify(b_state->sam_ctx, msg); if (ret != LDB_SUCCESS) { diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index 6a6bc8be7e..96cb58ef3e 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -60,7 +60,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C /* if this is a DC connecting, give them system level access */ werr = drs_security_level_check(dce_call, NULL); if (W_ERROR_IS_OK(werr)) { - DEBUG(2,(__location__ ": doing DsBind with system_session\n")); + DEBUG(3,(__location__ ": doing DsBind with system_session\n")); auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx); } else { auth_info = dce_call->conn->auth_state.session_info; @@ -378,81 +378,6 @@ static WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TA return WERR_UNKNOWN_LEVEL; } -/* - drsuapi_DsWriteAccountSpn -*/ -static WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct drsuapi_DsWriteAccountSpn *r) -{ - struct drsuapi_bind_state *b_state; - struct dcesrv_handle *h; - - *r->out.level_out = r->in.level; - - DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); - b_state = h->data; - - r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult); - W_ERROR_HAVE_NO_MEMORY(r->out.res); - - switch (r->in.level) { - case 1: { - struct drsuapi_DsWriteAccountSpnRequest1 *req; - struct ldb_message *msg; - int count, i, ret; - req = &r->in.req->req1; - count = req->count; - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - return WERR_NOMEM; - } - - msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn); - if ( ! ldb_dn_validate(msg->dn)) { - r->out.res->res1.status = WERR_OK; - return WERR_OK; - } - - /* construct mods */ - for (i = 0; i < count; i++) { - samdb_msg_add_string(b_state->sam_ctx, - msg, msg, "servicePrincipalName", - req->spn_names[i].str); - } - for (i=0;i<msg->num_elements;i++) { - switch (req->operation) { - case DRSUAPI_DS_SPN_OPERATION_ADD: - msg->elements[i].flags = LDB_FLAG_MOD_ADD; - break; - case DRSUAPI_DS_SPN_OPERATION_REPLACE: - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; - break; - case DRSUAPI_DS_SPN_OPERATION_DELETE: - msg->elements[i].flags = LDB_FLAG_MOD_DELETE; - break; - } - } - - /* Apply to database */ - - ret = ldb_modify(b_state->sam_ctx, msg); - if (ret != 0) { - DEBUG(0,("Failed to modify SPNs on %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(b_state->sam_ctx))); - r->out.res->res1.status = WERR_ACCESS_DENIED; - } else { - r->out.res->res1.status = WERR_OK; - } - - return WERR_OK; - } - } - - return WERR_UNKNOWN_LEVEL; -} - /* drsuapi_DsRemoveDSServer diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h index 3a64ef5c9c..ba6bb21145 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h @@ -47,6 +47,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ struct drsuapi_DsGetNCChanges *r); WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsAddEntry *r); +WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct drsuapi_DsWriteAccountSpn *r); char *drs_ObjectIdentifier_to_string(TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaObjectIdentifier *nc); diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 437dc87ae8..908060a0dd 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -30,6 +30,7 @@ #include "rpc_server/dcerpc_server_proto.h" #include "../libcli/drsuapi/drsuapi.h" #include "libcli/security/security.h" +#include "lib/util/binsearch.h" /* build a DsReplicaObjectIdentifier from a ldb msg @@ -57,6 +58,29 @@ static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CT return identifier; } +static int udv_compare(const struct GUID *guid1, struct GUID guid2) +{ + return GUID_compare(guid1, &guid2); +} + +/* + see if we can filter an attribute using the uptodateness_vector + */ +static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv, + const struct GUID *originating_invocation_id, + uint64_t originating_usn) +{ + const struct drsuapi_DsReplicaCursor *c; + if (udv == NULL) return false; + BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id, + originating_invocation_id, udv_compare, c); + if (c && originating_usn <= c->highest_usn) { + return true; + } + return false; + +} + /* drsuapi_DsGetNCChanges for one object */ @@ -67,7 +91,8 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem struct dsdb_schema *schema, DATA_BLOB *session_key, uint64_t highest_usn, - uint32_t replica_flags) + uint32_t replica_flags, + struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector) { const struct ldb_val *md_value; int i, n; @@ -77,8 +102,10 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem uint32_t *attids; const char *rdn; const struct dsdb_attribute *rdn_sa; + unsigned int instanceType; - if (ldb_dn_compare(ncRoot_dn, msg->dn) == 0) { + instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType", 0); + if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) { obj->is_nc_prefix = true; obj->parent_object_guid = NULL; } else { @@ -156,6 +183,14 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem } } + /* filter by uptodateness_vector */ + if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType && + udv_filter(uptodateness_vector, + &md.ctr.ctr1.array[i].originating_invocation_id, + md.ctr.ctr1.array[i].originating_usn)) { + continue; + } + obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time; obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version; obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id; @@ -164,11 +199,15 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem n++; } - /* - note that if n==0 we still need to send the change, as it - could be a rename, which changes the uSNChanged, but not any - of the replicated attributes - */ + /* ignore it if its an empty change. Note that renames always + * change the 'name' attribute, so they won't be ignored by + * this */ + if (n == 0 || + (n == 1 && attids[0] == DRSUAPI_ATTRIBUTE_instanceType)) { + talloc_free(obj->meta_data_ctr); + obj->meta_data_ctr = NULL; + return WERR_OK; + } obj->meta_data_ctr->count = n; @@ -302,7 +341,8 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, uint32_t replica_flags, struct ldb_message *msg, struct drsuapi_DsReplicaLinkedAttribute **la_list, - uint32_t *la_count) + uint32_t *la_count, + struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector) { int i; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); @@ -430,6 +470,10 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, struct replUpToDateVectorBlob ouv; int i; + udv->version = 2; + udv->reserved1 = 0; + udv->reserved2 = 0; + werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv); if (!W_ERROR_IS_OK(werr)) { return werr; @@ -564,6 +608,103 @@ static int site_res_cmp_usn_order(const struct ldb_message **m1, const struct ld } +/* + handle a DRSUAPI_EXOP_FSMO_RID_ALLOC call + */ +static WERROR getncchanges_rid_alloc(struct drsuapi_bind_state *b_state, + TALLOC_CTX *mem_ctx, + struct drsuapi_DsGetNCChangesRequest8 *req8, + struct drsuapi_DsGetNCChangesCtr6 *ctr6) +{ + struct ldb_dn *rid_manager_dn, *fsmo_role_dn, *req_dn; + int ret; + struct ldb_context *ldb = b_state->sam_ctx; + struct ldb_result *ext_res; + struct ldb_dn *base_dn; + struct dsdb_fsmo_extended_op *exop; + + /* + steps: + - verify that the DN being asked for is the RID Manager DN + - verify that we are the RID Manager + */ + + /* work out who is the RID Manager */ + ret = samdb_rid_manager_dn(ldb, mem_ctx, &rid_manager_dn); + if (ret != LDB_SUCCESS) { + DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb))); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + req_dn = ldb_dn_new(mem_ctx, ldb, req8->naming_context->dn); + if (!req_dn || + !ldb_dn_validate(req_dn) || + ldb_dn_compare(req_dn, rid_manager_dn) != 0) { + /* that isn't the RID Manager DN */ + DEBUG(0,(__location__ ": RID Alloc request for wrong DN %s\n", + req8->naming_context->dn)); + ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH; + return WERR_OK; + } + + /* find the DN of the RID Manager */ + ret = samdb_reference_dn(ldb, mem_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s\n", + ldb_errstring(ldb))); + ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER; + return WERR_DS_DRA_INTERNAL_ERROR; + } + + if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) { + /* we're not the RID Manager - go away */ + DEBUG(0,(__location__ ": RID Alloc request when not RID Manager\n")); + ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER; + return WERR_OK; + } + + exop = talloc(mem_ctx, struct dsdb_fsmo_extended_op); + W_ERROR_HAVE_NO_MEMORY(exop); + + exop->fsmo_info = req8->fsmo_info; + exop->destination_dsa_guid = req8->destination_dsa_guid; + + ret = ldb_transaction_start(ldb); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed transaction start - %s\n", + ldb_errstring(ldb))); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + ret = ldb_extended(ldb, DSDB_EXTENDED_ALLOCATE_RID_POOL, exop, &ext_res); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed extended allocation RID pool operation - %s\n", + ldb_errstring(ldb))); + ldb_transaction_cancel(ldb); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + ret = ldb_transaction_commit(ldb); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed transaction commit - %s\n", + ldb_errstring(ldb))); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + talloc_free(ext_res); + + base_dn = samdb_base_dn(ldb); + + DEBUG(2,("Allocated RID pool for server %s\n", + GUID_string(mem_ctx, &req8->destination_dsa_guid))); + + ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS; + + return WERR_OK; +} + + + /* state of a partially completed getncchanges call */ struct drsuapi_getncchanges_state { struct ldb_result *site_res; @@ -574,6 +715,7 @@ struct drsuapi_getncchanges_state { struct ldb_dn *last_dn; struct drsuapi_DsReplicaLinkedAttribute *la_list; uint32_t la_count; + struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector; }; /* @@ -609,6 +751,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ struct drsuapi_DsGetNCChangesRequest8 *req8; uint32_t options; uint32_t max_objects; + struct ldb_dn *search_dn = NULL; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; @@ -669,6 +812,28 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return werr; } + /* we don't yet support extended operations */ + switch (req8->extended_op) { + case DRSUAPI_EXOP_NONE: + break; + + case DRSUAPI_EXOP_FSMO_RID_ALLOC: + werr = getncchanges_rid_alloc(b_state, mem_ctx, req8, &r->out.ctr->ctr6); + W_ERROR_NOT_OK_RETURN(werr); + search_dn = samdb_base_dn(b_state->sam_ctx); + break; + + case DRSUAPI_EXOP_FSMO_REQ_ROLE: + case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE: + case DRSUAPI_EXOP_FSMO_REQ_PDC: + case DRSUAPI_EXOP_FSMO_ABANDON_ROLE: + case DRSUAPI_EXOP_REPL_OBJ: + case DRSUAPI_EXOP_REPL_SECRET: + DEBUG(0,(__location__ ": Request for DsGetNCChanges unsupported extended op 0x%x\n", + (unsigned)req8->extended_op)); + return WERR_DS_DRA_NOT_SUPPORTED; + } + getnc_state = b_state->getncchanges_state; /* see if a previous replication has been abandoned */ @@ -706,13 +871,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return WERR_DS_DRA_INTERNAL_ERROR; } - /* we don't yet support extended operations */ - if (req8->extended_op != DRSUAPI_EXOP_NONE) { - DEBUG(0,(__location__ ": Request for DsGetNCChanges extended op 0x%x\n", - (unsigned)req8->extended_op)); - return WERR_DS_DRA_NOT_SUPPORTED; - } - /* TODO: MS-DRSR section 4.1.10.1.1 Work out if this is the start of a new cycle */ @@ -745,10 +903,14 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ scope = LDB_SCOPE_BASE; } + if (!search_dn) { + search_dn = getnc_state->ncRoot_dn; + } + DEBUG(1,(__location__ ": getncchanges on %s using filter %s\n", ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter)); ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, &getnc_state->site_res, - getnc_state->ncRoot_dn, scope, attrs, + search_dn, scope, attrs, search_filter); if (ret != LDB_SUCCESS) { return WERR_DS_DRA_INTERNAL_ERROR; @@ -766,6 +928,14 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ (comparison_fn_t)site_res_cmp_usn_order); } + getnc_state->uptodateness_vector = talloc_steal(getnc_state, req8->uptodateness_vector); + if (getnc_state->uptodateness_vector) { + /* make sure its sorted */ + qsort(getnc_state->uptodateness_vector->cursors, + getnc_state->uptodateness_vector->count, + sizeof(getnc_state->uptodateness_vector->cursors[0]), + (comparison_fn_t)drsuapi_DsReplicaCursor_compare); + } } /* Prefix mapping */ @@ -821,7 +991,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ werr = get_nc_changes_build_object(obj, msg, b_state->sam_ctx, getnc_state->ncRoot_dn, schema, &session_key, getnc_state->min_usn, - req8->replica_flags); + req8->replica_flags, getnc_state->uptodateness_vector); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -832,7 +1002,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ req8->replica_flags, msg, &getnc_state->la_list, - &getnc_state->la_count); + &getnc_state->la_count, + getnc_state->uptodateness_vector); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -846,7 +1017,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ } if (obj->meta_data_ctr == NULL) { - DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n", + DEBUG(8,(__location__ ": getncchanges skipping send of object %s\n", ldb_dn_get_linearized(msg->dn))); /* no attributes to send */ talloc_free(obj); @@ -902,10 +1073,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ b_state->sam_ctx, (ldb_qsort_cmp_fn_t)linked_attribute_compare); r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); - r->out.ctr->ctr6.uptodateness_vector->version = 2; - r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0; - r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0; - r->out.ctr->ctr6.new_highwatermark.highest_usn = r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn; werr = get_nc_changes_udv(b_state->sam_ctx, getnc_state->ncRoot_dn, @@ -919,6 +1086,12 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ b_state->getncchanges_state = NULL; } + if (req8->extended_op != DRSUAPI_EXOP_NONE) { + r->out.ctr->ctr6.uptodateness_vector = NULL; + r->out.ctr->ctr6.nc_object_count = 0; + ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark); + } + DEBUG(r->out.ctr->ctr6.more_data?2:1, ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d la=%d)\n", (unsigned long long)(req8->highwatermark.highest_usn+1), diff --git a/source4/rpc_server/drsuapi/writespn.c b/source4/rpc_server/drsuapi/writespn.c new file mode 100644 index 0000000000..8e20c88fae --- /dev/null +++ b/source4/rpc_server/drsuapi/writespn.c @@ -0,0 +1,145 @@ +/* + Unix SMB/CIFS implementation. + + implement the DsWriteAccountSpn call + + Copyright (C) Stefan Metzmacher 2009 + Copyright (C) Andrew Tridgell 2010 + + 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 "rpc_server/dcerpc_server.h" +#include "dsdb/samdb/samdb.h" +#include "rpc_server/drsuapi/dcesrv_drsuapi.h" + +/* + drsuapi_DsWriteAccountSpn +*/ +WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct drsuapi_DsWriteAccountSpn *r) +{ + struct drsuapi_bind_state *b_state; + struct dcesrv_handle *h; + + *r->out.level_out = r->in.level; + + DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); + b_state = h->data; + + r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult); + W_ERROR_HAVE_NO_MEMORY(r->out.res); + + switch (r->in.level) { + case 1: { + struct drsuapi_DsWriteAccountSpnRequest1 *req; + struct ldb_message *msg; + int count, i, ret; + struct ldb_result *res; + const char *attrs[] = { "servicePrincipalName", NULL }; + struct ldb_message_element *el; + unsigned spn_count=0; + + req = &r->in.req->req1; + count = req->count; + + msg = ldb_msg_new(mem_ctx); + if (msg == NULL) { + return WERR_NOMEM; + } + + msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn); + if ( ! ldb_dn_validate(msg->dn)) { + r->out.res->res1.status = WERR_OK; + return WERR_OK; + } + + /* load the existing SPNs, as these are + * ignored for adds and deletes (see MS-DRSR + * section 4.1.28.3) + */ + ret = ldb_search(b_state->sam_ctx, msg, &res, msg->dn, LDB_SCOPE_BASE, + attrs, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(0,("Failed to load existing SPNs on %s: %s\n", + ldb_dn_get_linearized(msg->dn), + ldb_errstring(b_state->sam_ctx))); + r->out.res->res1.status = WERR_DS_OBJ_NOT_FOUND; + return WERR_OK; + } + el = ldb_msg_find_element(res->msgs[0], "servicePrincipalName"); + + /* construct mods */ + for (i = 0; i < count; i++) { + bool found = false; + int j; + for (j=0; el && j<el->num_values; j++) { + if (samdb_ldb_val_case_cmp(req->spn_names[i].str, &el->values[j]) == 0) { + found = true; + break; + } + } + if ((req->operation == DRSUAPI_DS_SPN_OPERATION_ADD && found) || + (req->operation == DRSUAPI_DS_SPN_OPERATION_DELETE && !found)) { + continue; + } + ret = samdb_msg_add_string(b_state->sam_ctx, + msg, msg, "servicePrincipalName", + req->spn_names[i].str); + if (ret != LDB_SUCCESS) { + return WERR_NOMEM; + } + spn_count++; + } + + if (msg->num_elements == 0) { + DEBUG(2,("No SPNs need changing on %s\n", ldb_dn_get_linearized(msg->dn))); + r->out.res->res1.status = WERR_OK; + return WERR_OK; + } + + for (i=0;i<msg->num_elements;i++) { + switch (req->operation) { + case DRSUAPI_DS_SPN_OPERATION_ADD: + msg->elements[i].flags = LDB_FLAG_MOD_ADD; + break; + case DRSUAPI_DS_SPN_OPERATION_REPLACE: + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + break; + case DRSUAPI_DS_SPN_OPERATION_DELETE: + msg->elements[i].flags = LDB_FLAG_MOD_DELETE; + break; + } + } + + /* Apply to database */ + + ret = ldb_modify(b_state->sam_ctx, msg); + if (ret != 0) { + DEBUG(0,("Failed to modify SPNs on %s: %s\n", + ldb_dn_get_linearized(msg->dn), + ldb_errstring(b_state->sam_ctx))); + r->out.res->res1.status = WERR_ACCESS_DENIED; + } else { + DEBUG(2,("Modified %u SPNs on %s\n", spn_count, ldb_dn_get_linearized(msg->dn))); + r->out.res->res1.status = WERR_OK; + } + + return WERR_OK; + } + } + + return WERR_UNKNOWN_LEVEL; +} |