Ignore:
Timestamp:
Nov 27, 2012, 4:43:17 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: updated trunk to 3.6.0

Location:
trunk/server
Files:
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/server

  • trunk/server/source4/rpc_server/drsuapi/addentry.c

    r414 r745  
    2323#include "includes.h"
    2424#include "rpc_server/dcerpc_server.h"
    25 #include "rpc_server/common/common.h"
    2625#include "dsdb/samdb/samdb.h"
    27 #include "lib/ldb/include/ldb_errors.h"
     26#include "dsdb/common/util.h"
    2827#include "param/param.h"
    29 #include "librpc/gen_ndr/ndr_drsblobs.h"
    30 #include "auth/auth.h"
     28#include "libcli/security/security.h"
     29#include "libcli/security/session.h"
    3130#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
    32 #include "libcli/security/security.h"
    33 #include "librpc/gen_ndr/ndr_drsblobs.h"
    3431#include "librpc/gen_ndr/ndr_drsuapi.h"
    35 
    3632
    3733/*
     
    5046                const char *dn_string = obj->object.identifier->dn;
    5147                struct ldb_dn *dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, dn_string);
    52                 struct ldb_result *res;
     48                struct ldb_result *res, *res2;
    5349                struct ldb_dn *ref_dn;
    5450                struct GUID ntds_guid;
     
    5753                const char *ntds_guid_str;
    5854                const char *dom_string;
     55                const char *attrs2[] = { "dNSHostName", "cn", NULL };
     56                const char *dNSHostName, *cn;
    5957
    6058                DEBUG(6,(__location__ ": Adding SPNs for %s\n",
     
    8381                ntds_guid_str = GUID_string(res, &ntds_guid);
    8482
    85                 dom_string = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
     83                dom_string = lpcfg_dnsdomain(dce_call->conn->dce_ctx->lp_ctx);
     84
     85                /* get the dNSHostName and cn */
     86                ret = ldb_search(b_state->sam_ctx, mem_ctx, &res2,
     87                                 ref_dn, LDB_SCOPE_BASE, attrs2, NULL);
     88                if (ret != LDB_SUCCESS) {
     89                        DEBUG(0,(__location__ ": Failed to find ref_dn '%s'\n",
     90                                 ldb_dn_get_linearized(ref_dn)));
     91                        return WERR_DS_DRA_INTERNAL_ERROR;
     92                }
     93
     94                dNSHostName = ldb_msg_find_attr_as_string(res2->msgs[0], "dNSHostName", NULL);
     95                cn = ldb_msg_find_attr_as_string(res2->msgs[0], "cn", NULL);
    8696
    8797                /*
     
    101111                }
    102112
    103                 el->num_values = 2;
    104                 el->values = talloc_array(msg->elements, struct ldb_val, 2);
    105                 if (el->values == NULL) {
     113
     114                ldb_msg_add_steal_string(msg, "servicePrincipalName",
     115                                         talloc_asprintf(el->values,
     116                                                         "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s",
     117                                                         ntds_guid_str, dom_string));
     118                ldb_msg_add_steal_string(msg, "servicePrincipalName",
     119                                         talloc_asprintf(el->values, "ldap/%s._msdcs.%s",
     120                                                         ntds_guid_str, dom_string));
     121                if (cn) {
     122                        ldb_msg_add_steal_string(msg, "servicePrincipalName",
     123                                                 talloc_asprintf(el->values, "ldap/%s", cn));
     124                }
     125                if (dNSHostName) {
     126                        ldb_msg_add_steal_string(msg, "servicePrincipalName",
     127                                                 talloc_asprintf(el->values, "ldap/%s", dNSHostName));
     128                }
     129                if (el->num_values < 2) {
    106130                        return WERR_NOMEM;
    107131                }
    108                 /* the magic constant is the GUID of the DRSUAPI RPC
    109                    interface */
    110                 el->values[0].data = (uint8_t *)talloc_asprintf(el->values,
    111                                                                 "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s",
    112                                                                 ntds_guid_str, dom_string);
    113                 el->values[0].length = strlen((char *)el->values[0].data);
    114                 el->values[1].data = (uint8_t *)talloc_asprintf(el->values, "ldap/%s._msdcs.%s",
    115                                                                 ntds_guid_str, dom_string);
    116                 el->values[1].length = strlen((char *)el->values[1].data);
    117 
    118                 ret = ldb_modify(b_state->sam_ctx, msg);
     132
     133                ret = dsdb_modify(b_state->sam_ctx, msg, DSDB_MODIFY_PERMISSIVE);
    119134                if (ret != LDB_SUCCESS) {
    120135                        DEBUG(0,(__location__ ": Failed to add SPNs - %s\n",
     
    152167        ZERO_STRUCTP(r->out.ctr);
    153168        *r->out.level_out = 3;
    154         r->out.ctr->ctr3.level = 1;
    155         r->out.ctr->ctr3.error = talloc_zero(mem_ctx, union drsuapi_DsAddEntryError);
     169        r->out.ctr->ctr3.err_ver = 1;
     170        r->out.ctr->ctr3.err_data = talloc_zero(mem_ctx, union drsuapi_DsAddEntry_ErrData);
    156171
    157172        DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
    158173        b_state = h->data;
    159174
    160         status = drs_security_level_check(dce_call, "DsAddEntry");
     175        status = drs_security_level_check(dce_call, "DsAddEntry", SECURITY_DOMAIN_CONTROLLER, NULL);
    161176        if (!W_ERROR_IS_OK(status)) {
    162177                return status;
     
    179194                                                    &ids);
    180195                if (!W_ERROR_IS_OK(status)) {
    181                         r->out.ctr->ctr3.error->info1.status = status;
     196                        r->out.ctr->ctr3.err_data->v1.status = status;
    182197                        ldb_transaction_cancel(b_state->sam_ctx);
     198                        DEBUG(0,(__location__ ": DsAddEntry failed - %s\n", win_errstr(status)));
    183199                        return status;
    184200                }
     
    197213        status = drsuapi_add_SPNs(b_state, dce_call, mem_ctx, first_object);
    198214        if (!W_ERROR_IS_OK(status)) {
    199                 r->out.ctr->ctr3.error->info1.status = status;
     215                r->out.ctr->ctr3.err_data->v1.status = status;
    200216                ldb_transaction_cancel(b_state->sam_ctx);
     217                DEBUG(0,(__location__ ": DsAddEntry add SPNs failed - %s\n", win_errstr(status)));
    201218                return status;
    202219        }
     
    204221        ret = ldb_transaction_commit(b_state->sam_ctx);
    205222        if (ret != LDB_SUCCESS) {
     223                DEBUG(0,(__location__ ": DsAddEntry commit failed: %s\n",
     224                         ldb_errstring(b_state->sam_ctx)));
    206225                return WERR_DS_DRA_INTERNAL_ERROR;
    207226        }
  • trunk/server/source4/rpc_server/drsuapi/dcesrv_drsuapi.c

    r414 r745  
    2626#include "rpc_server/common/common.h"
    2727#include "dsdb/samdb/samdb.h"
     28#include "libcli/security/security.h"
     29#include "libcli/security/session.h"
    2830#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
    29 #include "libcli/security/security.h"
     31#include "auth/auth.h"
     32#include "param/param.h"
     33#include "lib/messaging/irpc.h"
     34
     35#define DRSUAPI_UNSUPPORTED(fname) do { \
     36        DEBUG(1,(__location__ ": Unsupported DRS call %s\n", #fname)); \
     37        if (DEBUGLVL(2)) NDR_PRINT_IN_DEBUG(fname, r); \
     38        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); \
     39} while (0)
    3040
    3141/*
     
    4858        uint32_t repl_epoch;
    4959        int ret;
     60        struct auth_session_info *auth_info;
     61        WERROR werr;
     62        bool connected_as_system = false;
    5063
    5164        r->out.bind_info = NULL;
     
    5568        W_ERROR_HAVE_NO_MEMORY(b_state);
    5669
     70        /* if this is a DC connecting, give them system level access */
     71        werr = drs_security_level_check(dce_call, NULL, SECURITY_DOMAIN_CONTROLLER, NULL);
     72        if (W_ERROR_IS_OK(werr)) {
     73                DEBUG(3,(__location__ ": doing DsBind with system_session\n"));
     74                auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
     75                connected_as_system = true;
     76        } else {
     77                auth_info = dce_call->conn->auth_state.session_info;
     78        }
     79
    5780        /*
    5881         * connect to the samdb
    5982         */
    60         b_state->sam_ctx = samdb_connect(b_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
     83        b_state->sam_ctx = samdb_connect(b_state, dce_call->event_ctx,
     84                                         dce_call->conn->dce_ctx->lp_ctx, auth_info, 0);
    6185        if (!b_state->sam_ctx) {
    6286                return WERR_FOOBAR;
     87        }
     88
     89        if (connected_as_system) {
     90                b_state->sam_ctx_system = b_state->sam_ctx;
     91        } else {
     92                /* an RODC also needs system samdb access for secret
     93                   attribute replication */
     94                werr = drs_security_level_check(dce_call, NULL, SECURITY_RO_DOMAIN_CONTROLLER,
     95                                                samdb_domain_sid(b_state->sam_ctx));
     96                if (W_ERROR_IS_OK(werr)) {
     97                        b_state->sam_ctx_system = samdb_connect(b_state, dce_call->event_ctx,
     98                                                                dce_call->conn->dce_ctx->lp_ctx,
     99                                                                system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
     100                        if (!b_state->sam_ctx_system) {
     101                                return WERR_FOOBAR;
     102                        }
     103                }
    63104        }
    64105
     
    95136                return WERR_DS_DRA_INTERNAL_ERROR;
    96137        }
    97         repl_epoch = samdb_result_uint(ntds_res->msgs[0], "ms-DS-ReplicationEpoch", 0);
     138        repl_epoch = ldb_msg_find_attr_as_uint(ntds_res->msgs[0],
     139                                               "ms-DS-ReplicationEpoch", 0);
    98140
    99141        /*
     
    147189        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
    148190        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
    149         if (0 /*domain.behavior_version == 2*/) {
    150                 /* TODO: find out how this is really triggered! */
    151                 b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
    152         }
     191        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
    153192        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
    154193        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
     
    160199        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
    161200        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
    162         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
     201        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5;
    163202        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
    164203        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
     
    173212        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
    174213#endif
     214        b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10;
    175215        b_state->local_info28.site_guid                 = site_guid;
    176216        b_state->local_info28.pid                       = pid;
     
    230270{
    231271        WERROR status;
    232 
    233         status = drs_security_level_check(dce_call, "DsReplicaSync");
     272        uint32_t timeout;
     273
     274        status = drs_security_level_check(dce_call, "DsReplicaSync", SECURITY_DOMAIN_CONTROLLER, NULL);
    234275        if (!W_ERROR_IS_OK(status)) {
    235276                return status;
    236277        }
    237278
    238         dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICASYNC,
     279        if (r->in.level != 1) {
     280                DEBUG(0,("DsReplicaSync called with unsupported level %d\n", r->in.level));
     281                return WERR_DS_DRA_INVALID_PARAMETER;
     282        }
     283
     284        if (r->in.req->req1.options & DRSUAPI_DRS_ASYNC_OP) {
     285                timeout = IRPC_CALL_TIMEOUT;
     286        } else {
     287                /*
     288                 * use Infinite time for timeout in case
     289                 * the caller made a sync call
     290                 */
     291                timeout = IRPC_CALL_TIMEOUT_INF;
     292        }
     293
     294        dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
     295                                     r, NDR_DRSUAPI_DSREPLICASYNC,
    239296                                     &ndr_table_drsuapi,
    240                                      "dreplsrv", "DsReplicaSync");
     297                                     "dreplsrv", "DsReplicaSync",
     298                                     timeout);
    241299
    242300        return WERR_OK;
     
    250308                                          struct drsuapi_DsReplicaAdd *r)
    251309{
    252         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     310        WERROR status;
     311
     312        status = drs_security_level_check(dce_call, "DsReplicaAdd", SECURITY_DOMAIN_CONTROLLER, NULL);
     313        if (!W_ERROR_IS_OK(status)) {
     314                return status;
     315        }
     316
     317        dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
     318                                     r, NDR_DRSUAPI_DSREPLICAADD,
     319                                     &ndr_table_drsuapi,
     320                                     "dreplsrv", "DsReplicaAdd",
     321                                     IRPC_CALL_TIMEOUT);
     322
     323        return WERR_OK;
    253324}
    254325
     
    260331                                          struct drsuapi_DsReplicaDel *r)
    261332{
    262         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     333        WERROR status;
     334
     335        status = drs_security_level_check(dce_call, "DsReplicaDel", SECURITY_DOMAIN_CONTROLLER, NULL);
     336        if (!W_ERROR_IS_OK(status)) {
     337                return status;
     338        }
     339
     340        dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
     341                                     r, NDR_DRSUAPI_DSREPLICADEL,
     342                                     &ndr_table_drsuapi,
     343                                     "dreplsrv", "DsReplicaDel",
     344                                     IRPC_CALL_TIMEOUT);
     345
     346        return WERR_OK;
    263347}
    264348
     
    270354                                          struct drsuapi_DsReplicaMod *r)
    271355{
    272         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     356        WERROR status;
     357
     358        status = drs_security_level_check(dce_call, "DsReplicaMod", SECURITY_DOMAIN_CONTROLLER, NULL);
     359        if (!W_ERROR_IS_OK(status)) {
     360                return status;
     361        }
     362
     363        dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
     364                                     r, NDR_DRSUAPI_DSREPLICAMOD,
     365                                     &ndr_table_drsuapi,
     366                                     "dreplsrv", "DsReplicaMod",
     367                                     IRPC_CALL_TIMEOUT);
     368
     369        return WERR_OK;
    273370}
    274371
     
    280377                       struct DRSUAPI_VERIFY_NAMES *r)
    281378{
    282         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     379        DRSUAPI_UNSUPPORTED(DRSUAPI_VERIFY_NAMES);
    283380}
    284381
     
    290387                       struct drsuapi_DsGetMemberships *r)
    291388{
    292         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     389        DRSUAPI_UNSUPPORTED(drsuapi_DsGetMemberships);
    293390}
    294391
     
    300397                       struct DRSUAPI_INTER_DOMAIN_MOVE *r)
    301398{
    302         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     399        DRSUAPI_UNSUPPORTED(DRSUAPI_INTER_DOMAIN_MOVE);
    303400}
    304401
     
    310407                       struct drsuapi_DsGetNT4ChangeLog *r)
    311408{
    312         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    313 }
    314 
     409        DRSUAPI_UNSUPPORTED(drsuapi_DsGetNT4ChangeLog);
     410}
    315411
    316412/*
     
    320416                            struct drsuapi_DsCrackNames *r)
    321417{
    322         WERROR status;
    323418        struct drsuapi_bind_state *b_state;
    324419        struct dcesrv_handle *h;
     
    334429        switch (r->in.level) {
    335430                case 1: {
    336                         struct drsuapi_DsNameCtr1 *ctr1;
    337                         struct drsuapi_DsNameInfo1 *names;
    338                         int count;
    339                         int i;
    340 
    341                         ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
    342                         W_ERROR_HAVE_NO_MEMORY(ctr1);
    343 
    344                         count = r->in.req->req1.count;
    345                         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
    346                         W_ERROR_HAVE_NO_MEMORY(names);
    347 
    348                         for (i=0; i < count; i++) {
    349                                 status = DsCrackNameOneName(b_state->sam_ctx, mem_ctx,
    350                                                             r->in.req->req1.format_flags,
    351                                                             r->in.req->req1.format_offered,
    352                                                             r->in.req->req1.format_desired,
    353                                                             r->in.req->req1.names[i].str,
    354                                                             &names[i]);
    355                                 if (!W_ERROR_IS_OK(status)) {
    356                                         return status;
    357                                 }
    358                         }
    359 
    360                         ctr1->count = count;
    361                         ctr1->array = names;
    362                         r->out.ctr->ctr1 = ctr1;
    363 
    364                         return WERR_OK;
    365                 }
    366         }
    367        
    368         return WERR_UNKNOWN_LEVEL;
    369 }
    370 
    371 /*
    372   drsuapi_DsWriteAccountSpn
    373 */
    374 static WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    375                        struct drsuapi_DsWriteAccountSpn *r)
    376 {
    377         struct drsuapi_bind_state *b_state;
    378         struct dcesrv_handle *h;
    379 
    380         *r->out.level_out = r->in.level;
    381 
    382         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
    383         b_state = h->data;
    384 
    385         r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult);
    386         W_ERROR_HAVE_NO_MEMORY(r->out.res);
    387 
    388         switch (r->in.level) {
    389                 case 1: {
    390                         struct drsuapi_DsWriteAccountSpnRequest1 *req;
    391                         struct ldb_message *msg;
    392                         int count, i, ret;
    393                         req = &r->in.req->req1;
    394                         count = req->count;
    395 
    396                         msg = ldb_msg_new(mem_ctx);
    397                         if (msg == NULL) {
    398                                 return WERR_NOMEM;
    399                         }
    400 
    401                         msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn);
    402                         if ( ! ldb_dn_validate(msg->dn)) {
    403                                 r->out.res->res1.status = WERR_OK;
     431                        switch(r->in.req->req1.format_offered){
     432                        case DRSUAPI_DS_NAME_FORMAT_UPN_AND_ALTSECID:
     433                        case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX:
     434                        case DRSUAPI_DS_NAME_FORMAT_LIST_GLOBAL_CATALOG_SERVERS:
     435                        case DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON:
     436                        case DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_WITH_DCS_IN_SITE:
     437                        case DRSUAPI_DS_NAME_FORMAT_STRING_SID_NAME:
     438                        case DRSUAPI_DS_NAME_FORMAT_ALT_SECURITY_IDENTITIES_NAME:
     439                        case DRSUAPI_DS_NAME_FORMAT_LIST_NCS:
     440                        case DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS:
     441                        case DRSUAPI_DS_NAME_FORMAT_MAP_SCHEMA_GUID:
     442                        case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN:
     443                        case DRSUAPI_DS_NAME_FORMAT_LIST_INFO_FOR_SERVER:
     444                        case DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_FOR_DOMAIN_IN_SITE:
     445                        case DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS_IN_SITE:
     446                        case DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_IN_SITE:
     447                        case DRSUAPI_DS_NAME_FORMAT_LIST_SITES:
     448                                DEBUG(0, ("DsCrackNames: Unsupported operation requested: %X",
     449                                          r->in.req->req1.format_offered));
    404450                                return WERR_OK;
    405                         }
    406                        
    407                         /* construct mods */
    408                         for (i = 0; i < count; i++) {
    409                                 samdb_msg_add_string(b_state->sam_ctx,
    410                                                      msg, msg, "servicePrincipalName",
    411                                                      req->spn_names[i].str);
    412                         }
    413                         for (i=0;i<msg->num_elements;i++) {
    414                                 switch (req->operation) {
    415                                 case DRSUAPI_DS_SPN_OPERATION_ADD:
    416                                         msg->elements[i].flags = LDB_FLAG_MOD_ADD;
    417                                         break;
    418                                 case DRSUAPI_DS_SPN_OPERATION_REPLACE:
    419                                         msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    420                                         break;
    421                                 case DRSUAPI_DS_SPN_OPERATION_DELETE:
    422                                         msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
    423                                         break;
    424                                 }
    425                         }
    426    
    427                         /* Apply to database */
    428 
    429                         ret = ldb_modify(b_state->sam_ctx, msg);
    430                         if (ret != 0) {
    431                                 DEBUG(0,("Failed to modify SPNs on %s: %s\n",
    432                                          ldb_dn_get_linearized(msg->dn),
    433                                          ldb_errstring(b_state->sam_ctx)));
    434                                 r->out.res->res1.status = WERR_ACCESS_DENIED;
    435                         } else {
    436                                 r->out.res->res1.status = WERR_OK;
    437                         }
    438 
    439                         return WERR_OK;
    440                 }
    441         }
    442        
     451                        case DRSUAPI_DS_NAME_FORMAT_LIST_ROLES:
     452                                return dcesrv_drsuapi_ListRoles(b_state->sam_ctx, mem_ctx,
     453                                                                &r->in.req->req1, &r->out.ctr->ctr1);
     454                        default:/* format_offered is in the enum drsuapi_DsNameFormat*/
     455                                return dcesrv_drsuapi_CrackNamesByNameFormat(b_state->sam_ctx, mem_ctx,
     456                                                                             &r->in.req->req1, &r->out.ctr->ctr1);
     457                        }
     458                }
     459        }
    443460        return WERR_UNKNOWN_LEVEL;
    444461}
     
    458475        WERROR status;
    459476
    460         ZERO_STRUCT(r->out.res);
    461477        *r->out.level_out = 1;
    462478
    463         status = drs_security_level_check(dce_call, "DsRemoveDSServer");
     479        status = drs_security_level_check(dce_call, "DsRemoveDSServer", SECURITY_DOMAIN_CONTROLLER, NULL);
    464480        if (!W_ERROR_IS_OK(status)) {
    465481                return status;
     
    508524                       struct DRSUAPI_REMOVE_DS_DOMAIN *r)
    509525{
    510         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     526        DRSUAPI_UNSUPPORTED(DRSUAPI_REMOVE_DS_DOMAIN);
    511527}
    512528
    513529/* Obtain the site name from a server DN */
    514 static const char *result_site_name(struct ldb_dn *site_dn)
     530static const char *result_site_name(struct ldb_dn *server_dn)
    515531{
    516532        /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
    517         const struct ldb_val *val = ldb_dn_get_component_val(site_dn, 2);
    518         const char *name = ldb_dn_get_component_name(site_dn, 2);
     533        const struct ldb_val *val = ldb_dn_get_component_val(server_dn, 2);
     534        const char *name = ldb_dn_get_component_name(server_dn, 2);
    519535
    520536        if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
     
    556572        struct drsuapi_DsGetDCInfoCtr2 *ctr2;
    557573
    558         int ret, i;
     574        int ret;
     575        unsigned int i;
    559576
    560577        *r->out.level_out = r->in.req->req1.level;
     
    686703                        if (ret == LDB_SUCCESS && res_ntds->count == 1) {
    687704                                ctr2->array[i].is_gc
    688                                         = (ldb_msg_find_attr_as_int(res_ntds->msgs[0], "options", 0) == 1);
     705                                        = (ldb_msg_find_attr_as_uint(res_ntds->msgs[0], "options", 0) & DS_NTDSDSA_OPT_IS_GC);
    689706                                ctr2->array[i].ntds_guid
    690707                                        = samdb_result_guid(res_ntds->msgs[0], "objectGUID");
     
    784801                                  struct drsuapi_DsExecuteKCC *r)
    785802{
    786         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     803        WERROR status;
     804        status = drs_security_level_check(dce_call, "DsExecuteKCC", SECURITY_DOMAIN_CONTROLLER, NULL);
     805
     806        if (!W_ERROR_IS_OK(status)) {
     807                return status;
     808        }
     809
     810        dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSEXECUTEKCC,
     811                                     &ndr_table_drsuapi, "kccsrv", "DsExecuteKCC",
     812                                     IRPC_CALL_TIMEOUT);
     813        return WERR_OK;
    787814}
    788815
     
    794821                       struct drsuapi_DsReplicaGetInfo *r)
    795822{
    796         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     823        enum security_user_level level;
     824
     825        if (!lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL,
     826                         "drs", "disable_sec_check", false)) {
     827                level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
     828                if (level < SECURITY_DOMAIN_CONTROLLER) {
     829                        DEBUG(1,(__location__ ": Administrator access required for DsReplicaGetInfo\n"));
     830                        security_token_debug(0, 2, dce_call->conn->auth_state.session_info->security_token);
     831                        return WERR_DS_DRA_ACCESS_DENIED;
     832                }
     833        }
     834
     835        dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICAGETINFO,
     836                                     &ndr_table_drsuapi, "kccsrv", "DsReplicaGetInfo",
     837                                     IRPC_CALL_TIMEOUT);
     838
     839        return WERR_OK;
    797840}
    798841
     
    804847                       struct DRSUAPI_ADD_SID_HISTORY *r)
    805848{
    806         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     849        DRSUAPI_UNSUPPORTED(DRSUAPI_ADD_SID_HISTORY);
    807850}
    808851
     
    813856                       struct drsuapi_DsGetMemberships2 *r)
    814857{
    815         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     858        DRSUAPI_UNSUPPORTED(drsuapi_DsGetMemberships2);
    816859}
    817860
     
    822865                       struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
    823866{
    824         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     867        DRSUAPI_UNSUPPORTED(DRSUAPI_REPLICA_VERIFY_OBJECTS);
    825868}
    826869
     
    832875                       struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
    833876{
    834         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     877        DRSUAPI_UNSUPPORTED(DRSUAPI_GET_OBJECT_EXISTENCE);
    835878}
    836879
     
    842885                       struct drsuapi_QuerySitesByCost *r)
    843886{
    844         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     887        DRSUAPI_UNSUPPORTED(drsuapi_QuerySitesByCost);
    845888}
    846889
  • trunk/server/source4/rpc_server/drsuapi/dcesrv_drsuapi.h

    r414 r745  
    3232struct drsuapi_bind_state {
    3333        struct ldb_context *sam_ctx;
     34        struct ldb_context *sam_ctx_system;
    3435        struct GUID remote_bind_guid;
    3536        struct drsuapi_DsBindInfo28 remote_info28;
     
    4041
    4142/* prototypes of internal functions */
     43WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
     44                          struct drsuapi_DsReplicaUpdateRefsRequest1 *req);
    4245WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4346                                          struct drsuapi_DsReplicaUpdateRefs *r);
     
    4649WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4750                                 struct drsuapi_DsAddEntry *r);
     51WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     52                                        struct drsuapi_DsWriteAccountSpn *r);
    4853
    4954char *drs_ObjectIdentifier_to_string(TALLOC_CTX *mem_ctx,
     
    5661                                    enum ldb_scope scope,
    5762                                    const char * const *attrs,
    58                                     const char *sort_attrib,
    5963                                    const char *filter);
    6064
    6165WERROR drs_security_level_check(struct dcesrv_call_state *dce_call,
    62                                 const char* call);
     66                                const char* call, enum security_user_level minimum_level,
     67                                const struct dom_sid *domain_sid);
    6368
    6469void drsuapi_process_secret_attribute(struct drsuapi_DsReplicaAttribute *attr,
    6570                                      struct drsuapi_DsReplicaMetaData *meta_data);
     71
     72WERROR drs_security_access_check(struct ldb_context *sam_ctx,
     73                                 TALLOC_CTX *mem_ctx,
     74                                 struct security_token *token,
     75                                 struct drsuapi_DsReplicaObjectIdentifier *nc,
     76                                 const char *ext_right);
     77
     78WERROR drs_security_access_check_nc_root(struct ldb_context *sam_ctx,
     79                                         TALLOC_CTX *mem_ctx,
     80                                         struct security_token *token,
     81                                         struct drsuapi_DsReplicaObjectIdentifier *nc,
     82                                         const char *ext_right);
  • trunk/server/source4/rpc_server/drsuapi/drsutil.c

    r414 r745  
    2323#include "rpc_server/dcerpc_server.h"
    2424#include "dsdb/samdb/samdb.h"
    25 #include "libcli/security/dom_sid.h"
    26 #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
    2725#include "libcli/security/security.h"
     26#include "libcli/security/session.h"
    2827#include "param/param.h"
    29 
    30 /*
    31   format a drsuapi_DsReplicaObjectIdentifier naming context as a string
    32  */
    33 char *drs_ObjectIdentifier_to_string(TALLOC_CTX *mem_ctx,
    34                                      struct drsuapi_DsReplicaObjectIdentifier *nc)
    35 {
    36         char *guid, *sid, *ret;
    37         guid = GUID_string(mem_ctx, &nc->guid);
    38         sid  = dom_sid_string(mem_ctx, &nc->sid);
    39         ret = talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s",
    40                               guid, sid, nc->dn);
    41         talloc_free(guid);
    42         talloc_free(sid);
    43         return ret;
    44 }
     28#include "auth/session.h"
    4529
    4630int drsuapi_search_with_extended_dn(struct ldb_context *ldb,
     
    5034                                    enum ldb_scope scope,
    5135                                    const char * const *attrs,
    52                                     const char *sort_attrib,
    5336                                    const char *filter)
    5437{
     
    8467        }
    8568
    86         ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
    87         if (ret != LDB_SUCCESS) {
    88                 return ret;
    89         }
    90 
    91         if (sort_attrib) {
    92                 struct ldb_server_sort_control **sort_control;
    93                 sort_control = talloc_array(req, struct ldb_server_sort_control *, 2);
    94                 if (sort_control == NULL) {
    95                         talloc_free(tmp_ctx);
    96                         return LDB_ERR_OPERATIONS_ERROR;
    97                 }
    98                 sort_control[0] = talloc(req, struct ldb_server_sort_control);
    99                 sort_control[0]->attributeName = sort_attrib;
    100                 sort_control[0]->orderingRule = NULL;
    101                 sort_control[0]->reverse = 1;
    102                 sort_control[1] = NULL;
    103 
    104                 ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, sort_control);
    105                 if (ret != LDB_SUCCESS) {
    106                         return ret;
    107                 }
    108         }
    109 
     69        ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, true, NULL);
     70        if (ret != LDB_SUCCESS) {
     71                return ret;
     72        }
     73
     74        ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
     75        if (ret != LDB_SUCCESS) {
     76                return ret;
     77        }
    11078
    11179        ret = ldb_request(ldb, req);
     
    11987}
    12088
    121 WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, const char* call)
    122 {
    123         if (lp_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL,
     89WERROR drs_security_level_check(struct dcesrv_call_state *dce_call,
     90                                const char* call,
     91                                enum security_user_level minimum_level,
     92                                const struct dom_sid *domain_sid)
     93{
     94        enum security_user_level level;
     95
     96        if (lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL,
    12497                         "drs", "disable_sec_check", false)) {
    12598                return WERR_OK;
    12699        }
    127100
    128         if (security_session_user_level(dce_call->conn->auth_state.session_info) <
    129                 SECURITY_DOMAIN_CONTROLLER) {
    130                 DEBUG(0,("DsReplicaGetInfo refused for security token\n"));
     101        level = security_session_user_level(dce_call->conn->auth_state.session_info, domain_sid);
     102        if (level < minimum_level) {
     103                if (call) {
     104                        DEBUG(0,("%s refused for security token (level=%u)\n",
     105                                 call, (unsigned)level));
     106                        security_token_debug(0, 2, dce_call->conn->auth_state.session_info->security_token);
     107                }
    131108                return WERR_DS_DRA_ACCESS_DENIED;
    132109        }
     
    143120
    144121        switch (attr->attid) {
    145         case DRSUAPI_ATTRIBUTE_dBCSPwd:
    146         case DRSUAPI_ATTRIBUTE_unicodePwd:
    147         case DRSUAPI_ATTRIBUTE_ntPwdHistory:
    148         case DRSUAPI_ATTRIBUTE_lmPwdHistory:
    149         case DRSUAPI_ATTRIBUTE_supplementalCredentials:
    150         case DRSUAPI_ATTRIBUTE_priorValue:
    151         case DRSUAPI_ATTRIBUTE_currentValue:
    152         case DRSUAPI_ATTRIBUTE_trustAuthOutgoing:
    153         case DRSUAPI_ATTRIBUTE_trustAuthIncoming:
    154         case DRSUAPI_ATTRIBUTE_initialAuthOutgoing:
    155         case DRSUAPI_ATTRIBUTE_initialAuthIncoming:
     122        case DRSUAPI_ATTID_dBCSPwd:
     123        case DRSUAPI_ATTID_unicodePwd:
     124        case DRSUAPI_ATTID_ntPwdHistory:
     125        case DRSUAPI_ATTID_lmPwdHistory:
     126        case DRSUAPI_ATTID_supplementalCredentials:
     127        case DRSUAPI_ATTID_priorValue:
     128        case DRSUAPI_ATTID_currentValue:
     129        case DRSUAPI_ATTID_trustAuthOutgoing:
     130        case DRSUAPI_ATTID_trustAuthIncoming:
     131        case DRSUAPI_ATTID_initialAuthOutgoing:
     132        case DRSUAPI_ATTID_initialAuthIncoming:
    156133                /*set value to null*/
    157134                attr->value_ctr.num_values = 0;
     
    163140                return;
    164141        }
    165         return;
    166 }
     142}
     143
     144
     145/*
     146  check security on a DN, with logging of errors
     147 */
     148static WERROR drs_security_access_check_log(struct ldb_context *sam_ctx,
     149                                            TALLOC_CTX *mem_ctx,
     150                                            struct security_token *token,
     151                                            struct ldb_dn *dn,
     152                                            const char *ext_right)
     153{
     154        int ret;
     155        if (!dn) {
     156                DEBUG(3,("drs_security_access_check: Null dn provided, access is denied for %s\n",
     157                              ext_right));
     158                return WERR_DS_DRA_ACCESS_DENIED;
     159        }
     160        ret = dsdb_check_access_on_dn(sam_ctx,
     161                                      mem_ctx,
     162                                      dn,
     163                                      token,
     164                                      SEC_ADS_CONTROL_ACCESS,
     165                                      ext_right);
     166        if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     167                DEBUG(3,("%s refused for security token on %s\n",
     168                         ext_right, ldb_dn_get_linearized(dn)));
     169                security_token_debug(2, 0, token);
     170                return WERR_DS_DRA_ACCESS_DENIED;
     171        } else if (ret != LDB_SUCCESS) {
     172                DEBUG(1,("Failed to perform access check on %s\n", ldb_dn_get_linearized(dn)));
     173                return WERR_DS_DRA_INTERNAL_ERROR;
     174        }
     175        return WERR_OK;
     176}
     177
     178
     179/*
     180  check security on a object identifier
     181 */
     182WERROR drs_security_access_check(struct ldb_context *sam_ctx,
     183                                 TALLOC_CTX *mem_ctx,
     184                                 struct security_token *token,
     185                                 struct drsuapi_DsReplicaObjectIdentifier *nc,
     186                                 const char *ext_right)
     187{
     188        struct ldb_dn *dn = drs_ObjectIdentifier_to_dn(mem_ctx, sam_ctx, nc);
     189        WERROR werr;
     190        werr = drs_security_access_check_log(sam_ctx, mem_ctx, token, dn, ext_right);
     191        talloc_free(dn);
     192        return werr;
     193}
     194
     195/*
     196  check security on the NC root of a object identifier
     197 */
     198WERROR drs_security_access_check_nc_root(struct ldb_context *sam_ctx,
     199                                         TALLOC_CTX *mem_ctx,
     200                                         struct security_token *token,
     201                                         struct drsuapi_DsReplicaObjectIdentifier *nc,
     202                                         const char *ext_right)
     203{
     204        struct ldb_dn *dn, *nc_root;
     205        WERROR werr;
     206        int ret;
     207
     208        dn = drs_ObjectIdentifier_to_dn(mem_ctx, sam_ctx, nc);
     209        W_ERROR_HAVE_NO_MEMORY(dn);
     210        ret = dsdb_find_nc_root(sam_ctx, dn, dn, &nc_root);
     211        if (ret != LDB_SUCCESS) {
     212                return WERR_DS_CANT_FIND_EXPECTED_NC;
     213        }
     214        werr = drs_security_access_check_log(sam_ctx, mem_ctx, token, nc_root, ext_right);
     215        talloc_free(dn);
     216        return werr;
     217}
  • trunk/server/source4/rpc_server/drsuapi/getncchanges.c

    r414 r745  
    22   Unix SMB/CIFS implementation.
    33
    4    implement the DRSUpdateRefs call
     4   implement the DSGetNCChanges call
    55
    66   Copyright (C) Anatoliy Atanasov 2009
     
    2222
    2323#include "includes.h"
    24 #include "librpc/gen_ndr/ndr_drsuapi.h"
    2524#include "rpc_server/dcerpc_server.h"
    2625#include "dsdb/samdb/samdb.h"
    2726#include "param/param.h"
    2827#include "librpc/gen_ndr/ndr_drsblobs.h"
    29 #include "auth/auth.h"
     28#include "librpc/gen_ndr/ndr_drsuapi.h"
     29#include "librpc/gen_ndr/ndr_security.h"
     30#include "libcli/security/security.h"
     31#include "libcli/security/session.h"
    3032#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
    3133#include "rpc_server/dcerpc_server_proto.h"
    3234#include "../libcli/drsuapi/drsuapi.h"
    33 #include "libcli/security/security.h"
     35#include "lib/util/binsearch.h"
     36#include "lib/util/tsort.h"
     37#include "auth/session.h"
     38#include "dsdb/common/util.h"
     39
     40/*
     41  build a DsReplicaObjectIdentifier from a ldb msg
     42 */
     43static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CTX *mem_ctx,
     44                                                                       struct ldb_message *msg)
     45{
     46        struct drsuapi_DsReplicaObjectIdentifier *identifier;
     47        struct dom_sid *sid;
     48
     49        identifier = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
     50        if (identifier == NULL) {
     51                return NULL;
     52        }
     53
     54        identifier->dn = ldb_dn_alloc_linearized(identifier, msg->dn);
     55        identifier->guid = samdb_result_guid(msg, "objectGUID");
     56
     57        sid = samdb_result_dom_sid(identifier, msg, "objectSid");
     58        if (sid) {
     59                identifier->sid = *sid;
     60        } else {
     61                ZERO_STRUCT(identifier->sid);
     62        }
     63        return identifier;
     64}
     65
     66static int udv_compare(const struct GUID *guid1, struct GUID guid2)
     67{
     68        return GUID_compare(guid1, &guid2);
     69}
     70
     71/*
     72  see if we can filter an attribute using the uptodateness_vector
     73 */
     74static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
     75                       const struct GUID *originating_invocation_id,
     76                       uint64_t originating_usn)
     77{
     78        const struct drsuapi_DsReplicaCursor *c;
     79        if (udv == NULL) return false;
     80        BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id,
     81                            originating_invocation_id, udv_compare, c);
     82        if (c && originating_usn <= c->highest_usn) {
     83                return true;
     84        }
     85        return false;
     86       
     87}
     88
     89static int attid_cmp(enum drsuapi_DsAttributeId a1, enum drsuapi_DsAttributeId a2)
     90{
     91        if (a1 == a2) return 0;
     92        return ((uint32_t)a1) > ((uint32_t)a2) ? 1 : -1;
     93}
     94
     95/*
     96  check if an attribute is in a partial_attribute_set
     97 */
     98static bool check_partial_attribute_set(const struct dsdb_attribute *sa,
     99                                        struct drsuapi_DsPartialAttributeSet *pas)
     100{
     101        enum drsuapi_DsAttributeId *result;
     102        BINARY_ARRAY_SEARCH_V(pas->attids, pas->num_attids, (enum drsuapi_DsAttributeId)sa->attributeID_id,
     103                              attid_cmp, result);
     104        return result != NULL;
     105}
     106
    34107
    35108/*
     
    40113                                          struct ldb_context *sam_ctx,
    41114                                          struct ldb_dn *ncRoot_dn,
     115                                          bool   is_schema_nc,
    42116                                          struct dsdb_schema *schema,
    43117                                          DATA_BLOB *session_key,
    44118                                          uint64_t highest_usn,
    45                                           uint32_t replica_flags)
     119                                          uint32_t replica_flags,
     120                                          struct drsuapi_DsPartialAttributeSet *partial_attribute_set,
     121                                          struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
     122                                          enum drsuapi_DsExtendedOperation extended_op)
    46123{
    47124        const struct ldb_val *md_value;
    48         int i, n;
    49         struct ldb_dn *obj_dn;
     125        uint32_t i, n;
    50126        struct replPropertyMetaDataBlob md;
    51         struct dom_sid *sid;
    52127        uint32_t rid = 0;
    53128        enum ndr_err_code ndr_err;
     
    55130        const char *rdn;
    56131        const struct dsdb_attribute *rdn_sa;
    57 
    58         if (ldb_dn_compare(ncRoot_dn, msg->dn) == 0) {
     132        unsigned int instanceType;
     133        struct dsdb_syntax_ctx syntax_ctx;
     134
     135        /* make dsdb sytanx context for conversions */
     136        dsdb_syntax_ctx_init(&syntax_ctx, sam_ctx, schema);
     137        syntax_ctx.is_schema_nc = is_schema_nc;
     138
     139        instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType", 0);
     140        if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
    59141                obj->is_nc_prefix = true;
    60142                obj->parent_object_guid = NULL;
    61143        } else {
    62                 struct ldb_dn *parent_dn;
    63                 uint32_t instance_type;
    64 
    65                 instance_type = ldb_msg_find_attr_as_uint(msg, "instanceType", 0);
    66                 if (instance_type & INSTANCE_TYPE_IS_NC_HEAD) {
    67                         struct ldb_result *res;
    68                         int ret;
    69                         char *dnstr = ldb_dn_get_linearized(msg->dn);
    70                         msg->dn = ldb_dn_new(msg, sam_ctx, dnstr);
    71                         /* we need to re-search the msg, to avoid the
    72                          * broken dual message problems with our
    73                          * partitions implementation */
    74                         DEBUG(6,(__location__ ": Re-fetching subref %s\n",
    75                                  ldb_dn_get_linearized(msg->dn)));
    76                         ret = drsuapi_search_with_extended_dn(sam_ctx, msg, &res,
    77                                                               msg->dn, LDB_SCOPE_BASE, NULL,
    78                                                               NULL, NULL);
    79                         if (ret != LDB_SUCCESS || res->count < 1) {
    80                                 DEBUG(0,(__location__ ": Failed to reload subref head %s in %s\n",
    81                                          ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ncRoot_dn)));
    82                                 return WERR_DS_DRA_INTERNAL_ERROR;
    83                         }
    84                         msg = res->msgs[0];
    85                 }
    86 
    87                 parent_dn = ldb_dn_copy(msg, msg->dn);
    88144                obj->is_nc_prefix = false;
    89145                obj->parent_object_guid = talloc(obj, struct GUID);
    90                 if (parent_dn == NULL) {
     146                if (obj->parent_object_guid == NULL) {
    91147                        return WERR_DS_DRA_INTERNAL_ERROR;
    92148                }
    93                 if (ldb_dn_remove_child_components(parent_dn, 1) != true) {
    94                         DEBUG(0,(__location__ ": Unable to remove DN component\n"));
     149                *obj->parent_object_guid = samdb_result_guid(msg, "parentGUID");
     150                if (GUID_all_zero(obj->parent_object_guid)) {
     151                        DEBUG(0,(__location__ ": missing parentGUID for %s\n",
     152                                 ldb_dn_get_linearized(msg->dn)));
    95153                        return WERR_DS_DRA_INTERNAL_ERROR;
    96154                }
    97                 if (dsdb_find_guid_by_dn(sam_ctx, parent_dn, obj->parent_object_guid) != LDB_SUCCESS) {
    98                         DEBUG(0,(__location__ ": Unable to find parent DN %s %s\n",
    99                                  ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(parent_dn)));
    100                 }
    101                 talloc_free(parent_dn);
    102155        }
    103156        obj->next_object = NULL;
     
    109162        }
    110163
    111         ndr_err = ndr_pull_struct_blob(md_value, obj,
    112                                        lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), &md,
     164        if (instanceType & INSTANCE_TYPE_UNINSTANT) {
     165                /* don't send uninstantiated objects */
     166                return WERR_OK;
     167        }
     168
     169        ndr_err = ndr_pull_struct_blob(md_value, obj, &md,
    113170                                       (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
    114171        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     
    135192        obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr);
    136193        attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count);
     194
     195        obj->object.identifier = get_object_identifier(obj, msg);
     196        if (obj->object.identifier == NULL) {
     197                return WERR_NOMEM;
     198        }
     199        dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid);
    137200       
    138201        obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count);
    139202        for (n=i=0; i<md.ctr.ctr1.count; i++) {
     203                const struct dsdb_attribute *sa;
     204                bool force_attribute = false;
     205
    140206                /* if the attribute has not changed, and it is not the
    141207                   instanceType then don't include it */
    142208                if (md.ctr.ctr1.array[i].local_usn < highest_usn &&
    143                     md.ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) continue;
     209                    extended_op != DRSUAPI_EXOP_REPL_SECRET &&
     210                    md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) continue;
     211
    144212                /* don't include the rDN */
    145213                if (md.ctr.ctr1.array[i].attid == rdn_sa->attributeID_id) continue;
     214
     215                sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid);
     216                if (!sa) {
     217                        DEBUG(0,(__location__ ": Failed to find attribute in schema for attrid %u mentioned in replPropertyMetaData of %s\n",
     218                                 (unsigned int)md.ctr.ctr1.array[i].attid,
     219                                 ldb_dn_get_linearized(msg->dn)));
     220                        return WERR_DS_DRA_INTERNAL_ERROR;             
     221                }
     222
     223                if (sa->linkID) {
     224                        struct ldb_message_element *el;
     225                        el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
     226                        if (el && el->num_values && dsdb_dn_is_upgraded_link_val(&el->values[0])) {
     227                                /* don't send upgraded links inline */
     228                                continue;
     229                        }
     230                }
     231
     232                if (extended_op == DRSUAPI_EXOP_REPL_SECRET &&
     233                    !dsdb_attr_in_rodc_fas(sa)) {
     234                        force_attribute = true;
     235                        DEBUG(4,("Forcing attribute %s in %s\n",
     236                                 sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     237                }
     238
     239                /* filter by uptodateness_vector */
     240                if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType &&
     241                    !force_attribute &&
     242                    udv_filter(uptodateness_vector,
     243                               &md.ctr.ctr1.array[i].originating_invocation_id,
     244                               md.ctr.ctr1.array[i].originating_usn)) {
     245                        continue;
     246                }
     247
     248                /* filter by partial_attribute_set */
     249                if (partial_attribute_set && !check_partial_attribute_set(sa, partial_attribute_set)) {
     250                        continue;
     251                }
     252
    146253                obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time;
    147254                obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version;
     
    152259        }
    153260
    154         /*
    155           note that if n==0 we still need to send the change, as it
    156           could be a rename, which changes the uSNChanged, but not any
    157           of the replicated attributes
    158          */
     261        /* ignore it if its an empty change. Note that renames always
     262         * change the 'name' attribute, so they won't be ignored by
     263         * this */
     264        if (n == 0 ||
     265            (n == 1 && attids[0] == DRSUAPI_ATTID_instanceType)) {
     266                talloc_free(obj->meta_data_ctr);
     267                obj->meta_data_ctr = NULL;
     268                return WERR_OK;
     269        }
    159270
    160271        obj->meta_data_ctr->count = n;
    161 
    162         obj->object.identifier = talloc(obj, struct drsuapi_DsReplicaObjectIdentifier);
    163         obj_dn = ldb_msg_find_attr_as_dn(sam_ctx, obj, msg, "distinguishedName");
    164         obj->object.identifier->dn = ldb_dn_get_linearized(obj_dn);
    165         obj->object.identifier->guid = samdb_result_guid(msg, "objectGUID");
    166         sid = samdb_result_dom_sid(obj, msg, "objectSid");
    167         if (sid) {
    168                 dom_sid_split_rid(NULL, sid, NULL, &rid);
    169                 obj->object.identifier->sid = *sid;
    170         } else {
    171                 ZERO_STRUCT(obj->object.identifier->sid);
    172         }
    173272
    174273        obj->object.flags = DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER;
     
    194293                el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
    195294                if (el == NULL) {
    196                         DEBUG(0,("No element '%s' for attributeID %u in message\n",
     295                        /* this happens for attributes that have been removed */
     296                        DEBUG(5,("No element '%s' for attributeID %u in message\n",
    197297                                 sa->lDAPDisplayName, attids[i]));
    198298                        ZERO_STRUCT(obj->object.attribute_ctr.attributes[i]);
    199                         obj->object.attribute_ctr.attributes[i].attid = attids[i];
     299                        obj->object.attribute_ctr.attributes[i].attid =
     300                                        dsdb_attribute_get_attid(sa, syntax_ctx.is_schema_nc);
    200301                } else {
    201                         werr = dsdb_attribute_ldb_to_drsuapi(sam_ctx, schema, el, obj,
    202                                                              &obj->object.attribute_ctr.attributes[i]);
     302                        werr = sa->syntax->ldb_to_drsuapi(&syntax_ctx, sa, el, obj,
     303                                                          &obj->object.attribute_ctr.attributes[i]);
    203304                        if (!W_ERROR_IS_OK(werr)) {
    204305                                DEBUG(0,("Unable to convert %s to DRS object - %s\n",
     
    206307                                return werr;
    207308                        }
    208                         /* if DRSUAPI_DS_REPLICA_NEIGHBOUR_SPECIAL_SECRET_PROCESSING is set
     309                        /* if DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING is set
    209310                         * check if attribute is secret and send a null value
    210                          * TODO: check if we can make this in the database layer
    211311                         */
    212                         if ((replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_SPECIAL_SECRET_PROCESSING)
    213                             == DRSUAPI_DS_REPLICA_NEIGHBOUR_SPECIAL_SECRET_PROCESSING) {
     312                        if (replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
    214313                                drsuapi_process_secret_attribute(&obj->object.attribute_ctr.attributes[i],
    215314                                                                 &obj->meta_data_ctr->meta_data[i]);
     
    230329}
    231330
     331
    232332/*
    233   load replUpToDateVector from a DN
     333  add one linked attribute from an object to the list of linked
     334  attributes in a getncchanges request
    234335 */
    235 static WERROR load_udv(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    236                        struct ldb_dn *dn, struct replUpToDateVectorBlob *ouv)
    237 {
    238         const char *attrs[] = { "replUpToDateVector", NULL };
    239         struct ldb_result *res = NULL;
     336static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx,
     337                                    struct ldb_context *sam_ctx,
     338                                    const struct dsdb_schema *schema,
     339                                    const struct dsdb_attribute *sa,
     340                                    struct ldb_message *msg,
     341                                    struct dsdb_dn *dsdb_dn,
     342                                    struct drsuapi_DsReplicaLinkedAttribute **la_list,
     343                                    uint32_t *la_count)
     344{
     345        struct drsuapi_DsReplicaLinkedAttribute *la;
     346        bool active;
     347        NTSTATUS status;
     348        WERROR werr;
     349
     350        (*la_list) = talloc_realloc(mem_ctx, *la_list, struct drsuapi_DsReplicaLinkedAttribute, (*la_count)+1);
     351        W_ERROR_HAVE_NO_MEMORY(*la_list);
     352
     353        la = &(*la_list)[*la_count];
     354
     355        la->identifier = get_object_identifier(*la_list, msg);
     356        W_ERROR_HAVE_NO_MEMORY(la->identifier);
     357
     358        active = (dsdb_dn_rmd_flags(dsdb_dn->dn) & DSDB_RMD_FLAG_DELETED) == 0;
     359
     360        la->attid = sa->attributeID_id;
     361        la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0;
     362
     363        status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->originating_add_time, "RMD_ADDTIME");
     364        if (!NT_STATUS_IS_OK(status)) {
     365                return ntstatus_to_werror(status);
     366        }
     367        status = dsdb_get_extended_dn_uint32(dsdb_dn->dn, &la->meta_data.version, "RMD_VERSION");
     368        if (!NT_STATUS_IS_OK(status)) {
     369                return ntstatus_to_werror(status);
     370        }
     371        status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->meta_data.originating_change_time, "RMD_CHANGETIME");
     372        if (!NT_STATUS_IS_OK(status)) {
     373                return ntstatus_to_werror(status);
     374        }
     375        status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &la->meta_data.originating_invocation_id, "RMD_INVOCID");
     376        if (!NT_STATUS_IS_OK(status)) {
     377                return ntstatus_to_werror(status);
     378        }
     379        status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &la->meta_data.originating_usn, "RMD_ORIGINATING_USN");
     380        if (!NT_STATUS_IS_OK(status)) {
     381                return ntstatus_to_werror(status);
     382        }
     383
     384        werr = dsdb_dn_la_to_blob(sam_ctx, sa, schema, *la_list, dsdb_dn, &la->value.blob);
     385        W_ERROR_NOT_OK_RETURN(werr);
     386
     387        (*la_count)++;
     388        return WERR_OK;
     389}
     390
     391
     392/*
     393  add linked attributes from an object to the list of linked
     394  attributes in a getncchanges request
     395 */
     396static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
     397                                       TALLOC_CTX *mem_ctx,
     398                                       struct ldb_dn *ncRoot_dn,
     399                                       struct dsdb_schema *schema,
     400                                       uint64_t highest_usn,
     401                                       uint32_t replica_flags,
     402                                       struct ldb_message *msg,
     403                                       struct drsuapi_DsReplicaLinkedAttribute **la_list,
     404                                       uint32_t *la_count,
     405                                       struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
     406{
     407        unsigned int i;
    240408        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    241         struct ldb_message_element *el;
    242         enum ndr_err_code ndr_err;
    243 
    244         ZERO_STRUCTP(ouv);
    245 
    246         if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
    247             res->count < 1) {
    248                 DEBUG(0,("load_udv: failed to read partition object\n"));
    249                 talloc_free(tmp_ctx);
    250                 return WERR_DS_DRA_INTERNAL_ERROR;
    251         }
    252 
    253         el = ldb_msg_find_element(res->msgs[0], "replUpToDateVector");
    254         if (el == NULL || el->num_values < 1) {
    255                 talloc_free(tmp_ctx);
    256                 ouv->version = 2;
    257                 return WERR_OK;
    258         }
    259 
    260         ndr_err = ndr_pull_struct_blob(&el->values[0],
    261                                        mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
    262                                        ouv,
    263                                        (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
     409        uint64_t uSNChanged = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1);
     410
     411        for (i=0; i<msg->num_elements; i++) {
     412                struct ldb_message_element *el = &msg->elements[i];
     413                const struct dsdb_attribute *sa;
     414                unsigned int j;
     415
     416                sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
     417
     418                if (!sa || sa->linkID == 0 || (sa->linkID & 1)) {
     419                        /* we only want forward links */
     420                        continue;
     421                }
     422
     423                if (el->num_values && !dsdb_dn_is_upgraded_link_val(&el->values[0])) {
     424                        /* its an old style link, it will have been
     425                         * sent in the main replication data */
     426                        continue;
     427                }
     428
     429                for (j=0; j<el->num_values; j++) {
     430                        struct dsdb_dn *dsdb_dn;
     431                        uint64_t local_usn;
     432                        NTSTATUS status;
     433                        WERROR werr;
     434
     435                        dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid);
     436                        if (dsdb_dn == NULL) {
     437                                DEBUG(1,(__location__ ": Failed to parse DN for %s in %s\n",
     438                                         el->name, ldb_dn_get_linearized(msg->dn)));
     439                                talloc_free(tmp_ctx);
     440                                return WERR_DS_DRA_INTERNAL_ERROR;
     441                        }
     442
     443                        status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &local_usn, "RMD_LOCAL_USN");
     444                        if (!NT_STATUS_IS_OK(status)) {
     445                                /* this can happen for attributes
     446                                   given to us with old style meta
     447                                   data */
     448                                continue;
     449                        }
     450
     451                        if (local_usn > uSNChanged) {
     452                                DEBUG(1,(__location__ ": uSNChanged less than RMD_LOCAL_USN for %s on %s\n",
     453                                         el->name, ldb_dn_get_linearized(msg->dn)));
     454                                talloc_free(tmp_ctx);
     455                                return WERR_DS_DRA_INTERNAL_ERROR;
     456                        }
     457
     458                        if (local_usn < highest_usn) {
     459                                continue;
     460                        }
     461
     462                        werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema, sa, msg,
     463                                                     dsdb_dn, la_list, la_count);
     464                        if (!W_ERROR_IS_OK(werr)) {
     465                                talloc_free(tmp_ctx);
     466                                return werr;
     467                        }
     468                }
     469        }
     470
    264471        talloc_free(tmp_ctx);
    265         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    266                 DEBUG(0,(__location__ ": Failed to parse replUpToDateVector for %s\n",
    267                          ldb_dn_get_linearized(dn)));
    268                 return WERR_DS_DRA_INTERNAL_ERROR;
    269         }
    270        
    271472        return WERR_OK;
    272        
    273473}
    274474
     
    280480                                 struct drsuapi_DsReplicaCursor2CtrEx *udv)
    281481{
     482        int ret;
     483
     484        udv->version = 2;
     485        udv->reserved1 = 0;
     486        udv->reserved2 = 0;
     487
     488        ret = dsdb_load_udv_v2(sam_ctx, ncRoot_dn, udv, &udv->cursors, &udv->count);
     489        if (ret != LDB_SUCCESS) {
     490                DEBUG(0,(__location__ ": Failed to load UDV for %s - %s\n",
     491                         ldb_dn_get_linearized(ncRoot_dn), ldb_errstring(sam_ctx)));
     492                return WERR_DS_DRA_INTERNAL_ERROR;
     493        }
     494       
     495        return WERR_OK;
     496}
     497
     498
     499/* comparison function for linked attributes - see CompareLinks() in
     500 * MS-DRSR section 4.1.10.5.17 */
     501static int linked_attribute_compare(const struct drsuapi_DsReplicaLinkedAttribute *la1,
     502                                    const struct drsuapi_DsReplicaLinkedAttribute *la2,
     503                                    struct ldb_context *sam_ctx)
     504{
     505        int c;
    282506        WERROR werr;
    283         struct drsuapi_DsReplicaCursor2 *tmp_cursor;
    284         uint64_t highest_commited_usn;
    285         NTTIME now;
    286         time_t t = time(NULL);
     507        TALLOC_CTX *tmp_ctx;
     508        const struct dsdb_schema *schema;
     509        const struct dsdb_attribute *schema_attrib;
     510        struct dsdb_dn *dn1, *dn2;
     511        struct GUID guid1, guid2;
     512        NTSTATUS status;
     513
     514        c = GUID_compare(&la1->identifier->guid,
     515                         &la2->identifier->guid);
     516        if (c != 0) return c;
     517
     518        if (la1->attid != la2->attid) {
     519                return la1->attid < la2->attid? -1:1;
     520        }
     521
     522        if ((la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) !=
     523            (la2->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) {
     524                return (la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1;
     525        }
     526
     527        /* we need to get the target GUIDs to compare */
     528        tmp_ctx = talloc_new(sam_ctx);
     529
     530        schema = dsdb_get_schema(sam_ctx, tmp_ctx);
     531        schema_attrib = dsdb_attribute_by_attributeID_id(schema, la1->attid);
     532
     533        werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la1->value.blob, &dn1);
     534        if (!W_ERROR_IS_OK(werr)) {
     535                DEBUG(0,(__location__ ": Bad la1 blob in sort\n"));
     536                talloc_free(tmp_ctx);
     537                return 0;
     538        }
     539
     540        werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la2->value.blob, &dn2);
     541        if (!W_ERROR_IS_OK(werr)) {
     542                DEBUG(0,(__location__ ": Bad la2 blob in sort\n"));
     543                talloc_free(tmp_ctx);
     544                return 0;
     545        }
     546
     547        status = dsdb_get_extended_dn_guid(dn1->dn, &guid1, "GUID");
     548        if (!NT_STATUS_IS_OK(status)) {
     549                DEBUG(0,(__location__ ": Bad la1 guid in sort\n"));
     550                talloc_free(tmp_ctx);
     551                return 0;
     552        }
     553        status = dsdb_get_extended_dn_guid(dn2->dn, &guid2, "GUID");
     554        if (!NT_STATUS_IS_OK(status)) {
     555                DEBUG(0,(__location__ ": Bad la2 guid in sort\n"));
     556                talloc_free(tmp_ctx);
     557                return 0;
     558        }
     559
     560        talloc_free(tmp_ctx);
     561
     562        return GUID_compare(&guid1, &guid2);
     563}
     564
     565
     566/*
     567  sort the objects we send by tree order
     568 */
     569static int site_res_cmp_parent_order(struct ldb_message **m1, struct ldb_message **m2)
     570{
     571        return ldb_dn_compare((*m2)->dn, (*m1)->dn);
     572}
     573
     574/*
     575  sort the objects we send first by uSNChanged
     576 */
     577static int site_res_cmp_usn_order(struct ldb_message **m1, struct ldb_message **m2)
     578{
     579        unsigned usnchanged1, usnchanged2;
     580        unsigned cn1, cn2;
     581        cn1 = ldb_dn_get_comp_num((*m1)->dn);
     582        cn2 = ldb_dn_get_comp_num((*m2)->dn);
     583        if (cn1 != cn2) {
     584                return cn1 > cn2 ? 1 : -1;
     585        }
     586        usnchanged1 = ldb_msg_find_attr_as_uint(*m1, "uSNChanged", 0);
     587        usnchanged2 = ldb_msg_find_attr_as_uint(*m2, "uSNChanged", 0);
     588        if (usnchanged1 == usnchanged2) {
     589                return 0;
     590        }
     591        return usnchanged1 > usnchanged2 ? 1 : -1;
     592}
     593
     594
     595/*
     596  handle a DRSUAPI_EXOP_FSMO_RID_ALLOC call
     597 */
     598static WERROR getncchanges_rid_alloc(struct drsuapi_bind_state *b_state,
     599                                     TALLOC_CTX *mem_ctx,
     600                                     struct drsuapi_DsGetNCChangesRequest10 *req10,
     601                                     struct drsuapi_DsGetNCChangesCtr6 *ctr6)
     602{
     603        struct ldb_dn *rid_manager_dn, *fsmo_role_dn, *req_dn;
    287604        int ret;
    288         struct replUpToDateVectorBlob ouv;
    289 
    290         werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv);
     605        struct ldb_context *ldb = b_state->sam_ctx;
     606        struct ldb_result *ext_res;
     607        struct ldb_dn *base_dn;
     608        struct dsdb_fsmo_extended_op *exop;
     609
     610        /*
     611          steps:
     612            - verify that the DN being asked for is the RID Manager DN
     613            - verify that we are the RID Manager
     614         */
     615
     616        /* work out who is the RID Manager */
     617        ret = samdb_rid_manager_dn(ldb, mem_ctx, &rid_manager_dn);
     618        if (ret != LDB_SUCCESS) {
     619                DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
     620                return WERR_DS_DRA_INTERNAL_ERROR;
     621        }
     622
     623        req_dn = drs_ObjectIdentifier_to_dn(mem_ctx, ldb, req10->naming_context);
     624        if (!ldb_dn_validate(req_dn) ||
     625            ldb_dn_compare(req_dn, rid_manager_dn) != 0) {
     626                /* that isn't the RID Manager DN */
     627                DEBUG(0,(__location__ ": RID Alloc request for wrong DN %s\n",
     628                         drs_ObjectIdentifier_to_string(mem_ctx, req10->naming_context)));
     629                ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
     630                return WERR_OK;
     631        }
     632
     633        /* find the DN of the RID Manager */
     634        ret = samdb_reference_dn(ldb, mem_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
     635        if (ret != LDB_SUCCESS) {
     636                DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s\n",
     637                         ldb_errstring(ldb)));
     638                ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
     639                return WERR_DS_DRA_INTERNAL_ERROR;
     640        }
     641
     642        if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
     643                /* we're not the RID Manager - go away */
     644                DEBUG(0,(__location__ ": RID Alloc request when not RID Manager\n"));
     645                ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
     646                return WERR_OK;
     647        }
     648
     649        exop = talloc(mem_ctx, struct dsdb_fsmo_extended_op);
     650        W_ERROR_HAVE_NO_MEMORY(exop);
     651
     652        exop->fsmo_info = req10->fsmo_info;
     653        exop->destination_dsa_guid = req10->destination_dsa_guid;
     654
     655        ret = ldb_transaction_start(ldb);
     656        if (ret != LDB_SUCCESS) {
     657                DEBUG(0,(__location__ ": Failed transaction start - %s\n",
     658                         ldb_errstring(ldb)));
     659                return WERR_DS_DRA_INTERNAL_ERROR;
     660        }
     661
     662        /*
     663         * FIXME (kim): this is a temp hack to return just few object,
     664         * but not the whole domain NC.
     665         * We should remove this hack and implement a 'scope'
     666         * building function to return just the set of object
     667         * documented for DRSUAPI_EXOP_FSMO_RID_ALLOC extended_op
     668         */
     669        ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ, &req10->highwatermark.highest_usn);
     670
     671        ret = ldb_extended(ldb, DSDB_EXTENDED_ALLOCATE_RID_POOL, exop, &ext_res);
     672        if (ret != LDB_SUCCESS) {
     673                DEBUG(0,(__location__ ": Failed extended allocation RID pool operation - %s\n",
     674                         ldb_errstring(ldb)));
     675                ldb_transaction_cancel(ldb);
     676                return WERR_DS_DRA_INTERNAL_ERROR;
     677        }
     678
     679        ret = ldb_transaction_commit(ldb);
     680        if (ret != LDB_SUCCESS) {
     681                DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
     682                         ldb_errstring(ldb)));
     683                return WERR_DS_DRA_INTERNAL_ERROR;
     684        }
     685
     686        talloc_free(ext_res);
     687
     688        base_dn = ldb_get_default_basedn(ldb);
     689
     690        DEBUG(2,("Allocated RID pool for server %s\n",
     691                 GUID_string(mem_ctx, &req10->destination_dsa_guid)));
     692
     693        ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
     694
     695        return WERR_OK;
     696}
     697
     698/*
     699  return an array of SIDs from a ldb_message given an attribute name
     700  assumes the SIDs are in extended DN format
     701 */
     702static WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
     703                                        struct ldb_message *msg,
     704                                        TALLOC_CTX *mem_ctx,
     705                                        const char *attr,
     706                                        const struct dom_sid ***sids)
     707{
     708        struct ldb_message_element *el;
     709        unsigned int i;
     710
     711        el = ldb_msg_find_element(msg, attr);
     712        if (!el) {
     713                *sids = NULL;
     714                return WERR_OK;
     715        }
     716
     717        (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
     718        W_ERROR_HAVE_NO_MEMORY(*sids);
     719
     720        for (i=0; i<el->num_values; i++) {
     721                struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
     722                NTSTATUS status;
     723                struct dom_sid *sid;
     724
     725                sid = talloc(*sids, struct dom_sid);
     726                W_ERROR_HAVE_NO_MEMORY(sid);
     727                status = dsdb_get_extended_dn_sid(dn, sid, "SID");
     728                if (!NT_STATUS_IS_OK(status)) {
     729                        return WERR_INTERNAL_DB_CORRUPTION;
     730                }
     731                (*sids)[i] = sid;
     732        }
     733        (*sids)[i] = NULL;
     734
     735        return WERR_OK;
     736}
     737
     738
     739/*
     740  return an array of SIDs from a ldb_message given an attribute name
     741  assumes the SIDs are in NDR form
     742 */
     743static WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
     744                                         struct ldb_message *msg,
     745                                         TALLOC_CTX *mem_ctx,
     746                                         const char *attr,
     747                                         const struct dom_sid ***sids)
     748{
     749        struct ldb_message_element *el;
     750        unsigned int i;
     751
     752        el = ldb_msg_find_element(msg, attr);
     753        if (!el) {
     754                *sids = NULL;
     755                return WERR_OK;
     756        }
     757
     758        (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
     759        W_ERROR_HAVE_NO_MEMORY(*sids);
     760
     761        for (i=0; i<el->num_values; i++) {
     762                enum ndr_err_code ndr_err;
     763                struct dom_sid *sid;
     764
     765                sid = talloc(*sids, struct dom_sid);
     766                W_ERROR_HAVE_NO_MEMORY(sid);
     767
     768                ndr_err = ndr_pull_struct_blob(&el->values[i], sid, sid,
     769                                               (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
     770                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     771                        return WERR_INTERNAL_DB_CORRUPTION;
     772                }
     773                (*sids)[i] = sid;
     774        }
     775        (*sids)[i] = NULL;
     776
     777        return WERR_OK;
     778}
     779
     780/*
     781  see if any SIDs in list1 are in list2
     782 */
     783static bool sid_list_match(const struct dom_sid **list1, const struct dom_sid **list2)
     784{
     785        unsigned int i, j;
     786        /* do we ever have enough SIDs here to worry about O(n^2) ? */
     787        for (i=0; list1[i]; i++) {
     788                for (j=0; list2[j]; j++) {
     789                        if (dom_sid_equal(list1[i], list2[j])) {
     790                                return true;
     791                        }
     792                }
     793        }
     794        return false;
     795}
     796
     797/*
     798  handle a DRSUAPI_EXOP_REPL_SECRET call
     799 */
     800static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state,
     801                                       TALLOC_CTX *mem_ctx,
     802                                       struct drsuapi_DsGetNCChangesRequest10 *req10,
     803                                       struct dom_sid *user_sid,
     804                                       struct drsuapi_DsGetNCChangesCtr6 *ctr6)
     805{
     806        struct drsuapi_DsReplicaObjectIdentifier *ncRoot = req10->naming_context;
     807        struct ldb_dn *obj_dn, *rodc_dn, *krbtgt_link_dn;
     808        int ret;
     809        const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", NULL };
     810        const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
     811        struct ldb_result *rodc_res, *obj_res;
     812        const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids;
     813        WERROR werr;
     814
     815        DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n",
     816                 drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
     817
     818        /*
     819         * we need to work out if we will allow this RODC to
     820         * replicate the secrets for this object
     821         *
     822         * see 4.1.10.5.14 GetRevealSecretsPolicyForUser for details
     823         * of this function
     824         */
     825
     826        if (b_state->sam_ctx_system == NULL) {
     827                /* this operation needs system level access */
     828                ctr6->extended_ret = DRSUAPI_EXOP_ERR_ACCESS_DENIED;
     829                return WERR_DS_DRA_SOURCE_DISABLED;
     830        }
     831
     832        obj_dn = drs_ObjectIdentifier_to_dn(mem_ctx, b_state->sam_ctx_system, ncRoot);
     833        if (!ldb_dn_validate(obj_dn)) goto failed;
     834
     835        rodc_dn = ldb_dn_new_fmt(mem_ctx, b_state->sam_ctx_system, "<SID=%s>",
     836                                 dom_sid_string(mem_ctx, user_sid));
     837        if (!ldb_dn_validate(rodc_dn)) goto failed;
     838
     839        /* do the two searches we need */
     840        ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &rodc_res, rodc_dn, rodc_attrs,
     841                             DSDB_SEARCH_SHOW_EXTENDED_DN);
     842        if (ret != LDB_SUCCESS || rodc_res->count != 1) goto failed;
     843
     844        ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
     845        if (ret != LDB_SUCCESS || obj_res->count != 1) goto failed;
     846
     847        /* if the object SID is equal to the user_sid, allow */
     848        if (dom_sid_equal(user_sid,
     849                          samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid"))) {
     850                goto allowed;
     851        }
     852
     853        /* an RODC is allowed to get its own krbtgt account secrets */
     854        krbtgt_link_dn = samdb_result_dn(b_state->sam_ctx_system, mem_ctx,
     855                                         rodc_res->msgs[0], "msDS-KrbTgtLink", NULL);
     856        if (krbtgt_link_dn != NULL &&
     857            ldb_dn_compare(obj_dn, krbtgt_link_dn) == 0) {
     858                goto allowed;
     859        }
     860
     861        /* but it isn't allowed to get anyone elses krbtgt secrets */
     862        if (samdb_result_dn(b_state->sam_ctx_system, mem_ctx,
     863                            obj_res->msgs[0], "msDS-KrbTgtLinkBL", NULL)) {
     864                goto denied;
     865        }
     866
     867        if (ldb_msg_find_attr_as_uint(obj_res->msgs[0],
     868                                      "userAccountControl", 0) &
     869            UF_INTERDOMAIN_TRUST_ACCOUNT) {
     870                goto denied;
     871        }
     872
     873        werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0],
     874                                         mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids);
    291875        if (!W_ERROR_IS_OK(werr)) {
    292                 return werr;
    293         }
    294        
    295         ret = ldb_sequence_number(sam_ctx, LDB_SEQ_HIGHEST_SEQ, &highest_commited_usn);
     876                goto denied;
     877        }
     878
     879        werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0],
     880                                         mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids);
     881        if (!W_ERROR_IS_OK(werr)) {
     882                goto denied;
     883        }
     884
     885        werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0],
     886                                         mem_ctx, "tokenGroups", &token_sids);
     887        if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
     888                goto denied;
     889        }
     890
     891        if (never_reveal_sids &&
     892            sid_list_match(token_sids, never_reveal_sids)) {
     893                goto denied;
     894        }
     895
     896        if (reveal_sids &&
     897            sid_list_match(token_sids, reveal_sids)) {
     898                goto allowed;
     899        }
     900
     901        /* default deny */
     902denied:
     903        DEBUG(2,(__location__ ": Denied RODC secret replication for %s by RODC %s\n",
     904                 ldb_dn_get_linearized(obj_dn), ldb_dn_get_linearized(rodc_res->msgs[0]->dn)));
     905        ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
     906        return WERR_DS_DRA_ACCESS_DENIED;
     907
     908allowed:
     909        DEBUG(2,(__location__ ": Allowed RODC secret replication for %s by RODC %s\n",
     910                 ldb_dn_get_linearized(obj_dn), ldb_dn_get_linearized(rodc_res->msgs[0]->dn)));
     911        ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
     912        req10->highwatermark.highest_usn = 0;
     913        return WERR_OK;
     914
     915failed:
     916        DEBUG(2,(__location__ ": Failed RODC secret replication for %s by RODC %s\n",
     917                 ldb_dn_get_linearized(obj_dn), dom_sid_string(mem_ctx, user_sid)));
     918        ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
     919        return WERR_DS_DRA_BAD_DN;
     920}
     921
     922
     923/*
     924  handle a DRSUAPI_EXOP_REPL_OBJ call
     925 */
     926static WERROR getncchanges_repl_obj(struct drsuapi_bind_state *b_state,
     927                                    TALLOC_CTX *mem_ctx,
     928                                    struct drsuapi_DsGetNCChangesRequest10 *req10,
     929                                    struct dom_sid *user_sid,
     930                                    struct drsuapi_DsGetNCChangesCtr6 *ctr6)
     931{
     932        struct drsuapi_DsReplicaObjectIdentifier *ncRoot = req10->naming_context;
     933
     934        DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_OBJ extended op on %s\n",
     935                 drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
     936
     937        ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
     938        req10->highwatermark.highest_usn = 0;
     939        return WERR_OK;
     940}
     941
     942
     943/*
     944  handle DRSUAPI_EXOP_FSMO_REQ_ROLE,
     945  DRSUAPI_EXOP_FSMO_RID_REQ_ROLE,
     946  and DRSUAPI_EXOP_FSMO_REQ_PDC calls
     947 */
     948static WERROR getncchanges_change_master(struct drsuapi_bind_state *b_state,
     949                                         TALLOC_CTX *mem_ctx,
     950                                         struct drsuapi_DsGetNCChangesRequest10 *req10,
     951                                         struct drsuapi_DsGetNCChangesCtr6 *ctr6)
     952{
     953        struct ldb_dn *fsmo_role_dn, *req_dn, *ntds_dn;
     954        int ret;
     955        unsigned int i;
     956        struct ldb_context *ldb = b_state->sam_ctx;
     957        struct ldb_message *msg;
     958
     959        /*
     960          steps:
     961            - verify that the client dn exists
     962            - verify that we are the current master
     963         */
     964
     965        req_dn = drs_ObjectIdentifier_to_dn(mem_ctx, ldb, req10->naming_context);
     966        if (!ldb_dn_validate(req_dn)) {
     967                /* that is not a valid dn */
     968                DEBUG(0,(__location__ ": FSMO role transfer request for invalid DN %s\n",
     969                         drs_ObjectIdentifier_to_string(mem_ctx, req10->naming_context)));
     970                ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
     971                return WERR_OK;
     972        }
     973
     974        /* retrieve the current role owner */
     975        ret = samdb_reference_dn(ldb, mem_ctx, req_dn, "fSMORoleOwner", &fsmo_role_dn);
    296976        if (ret != LDB_SUCCESS) {
    297                 return WERR_DS_DRA_INTERNAL_ERROR;
    298         }
    299 
    300         tmp_cursor = talloc(udv, struct drsuapi_DsReplicaCursor2);
    301         tmp_cursor->source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
    302         tmp_cursor->highest_usn = highest_commited_usn;
    303         unix_to_nt_time(&now, t);
    304         tmp_cursor->last_sync_success = now;
    305 
    306         udv->count = ouv.ctr.ctr2.count + 1;
    307         udv->cursors = talloc_steal(udv, ouv.ctr.ctr2.cursors);
    308         udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count);
    309         if (!udv->cursors) {
    310                 return WERR_DS_DRA_INTERNAL_ERROR;
    311         }
    312         udv->cursors[udv->count - 1] = *tmp_cursor;
    313        
    314         qsort(udv->cursors, udv->count,
    315               sizeof(struct drsuapi_DsReplicaCursor2),
    316               (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
     977                DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in context - %s\n",
     978                         ldb_errstring(ldb)));
     979                ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
     980                return WERR_DS_DRA_INTERNAL_ERROR;
     981        }
     982
     983        if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
     984                /* we're not the current owner - go away */
     985                DEBUG(0,(__location__ ": FSMO transfer request when not owner\n"));
     986                ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
     987                return WERR_OK;
     988        }
     989
     990        /* change the current master */
     991        msg = ldb_msg_new(ldb);
     992        W_ERROR_HAVE_NO_MEMORY(msg);
     993        msg->dn = drs_ObjectIdentifier_to_dn(msg, ldb, req10->naming_context);
     994        W_ERROR_HAVE_NO_MEMORY(msg->dn);
     995
     996        ret = dsdb_find_dn_by_guid(ldb, msg, &req10->destination_dsa_guid, &ntds_dn);
     997        if (ret != LDB_SUCCESS) {
     998                DEBUG(0, (__location__ ": Unable to find NTDS object for guid %s - %s\n",
     999                          GUID_string(mem_ctx, &req10->destination_dsa_guid), ldb_errstring(ldb)));
     1000                talloc_free(msg);
     1001                return WERR_DS_DRA_INTERNAL_ERROR;
     1002        }
     1003
     1004        ret = ldb_msg_add_string(msg, "fSMORoleOwner", ldb_dn_get_linearized(ntds_dn));
     1005        if (ret != 0) {
     1006                talloc_free(msg);
     1007                return WERR_DS_DRA_INTERNAL_ERROR;
     1008        }
     1009
     1010        for (i=0;i<msg->num_elements;i++) {
     1011                msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
     1012        }
     1013
     1014        ret = ldb_transaction_start(ldb);
     1015        if (ret != LDB_SUCCESS) {
     1016                DEBUG(0,(__location__ ": Failed transaction start - %s\n",
     1017                         ldb_errstring(ldb)));
     1018                return WERR_DS_DRA_INTERNAL_ERROR;
     1019        }
     1020
     1021        ret = ldb_modify(ldb, msg);
     1022        if (ret != LDB_SUCCESS) {
     1023                DEBUG(0,(__location__ ": Failed to change current owner - %s\n",
     1024                         ldb_errstring(ldb)));
     1025                ldb_transaction_cancel(ldb);
     1026                return WERR_DS_DRA_INTERNAL_ERROR;
     1027        }
     1028
     1029        ret = ldb_transaction_commit(ldb);
     1030        if (ret != LDB_SUCCESS) {
     1031                DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
     1032                         ldb_errstring(ldb)));
     1033                return WERR_DS_DRA_INTERNAL_ERROR;
     1034        }
     1035
     1036        ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
    3171037
    3181038        return WERR_OK;
     
    3211041/* state of a partially completed getncchanges call */
    3221042struct drsuapi_getncchanges_state {
    323         struct ldb_result *site_res;
    324         uint32_t num_sent;
    325         struct ldb_context *sam_ctx;
     1043        struct GUID *guids;
     1044        uint32_t num_records;
     1045        uint32_t num_processed;
    3261046        struct ldb_dn *ncRoot_dn;
    327         uint32_t min_usn;
     1047        bool is_schema_nc;
     1048        uint64_t min_usn;
     1049        uint64_t highest_usn;
     1050        struct ldb_dn *last_dn;
     1051        struct drsuapi_DsReplicaLinkedAttribute *la_list;
     1052        uint32_t la_count;
     1053        bool la_sorted;
     1054        uint32_t la_idx;
     1055        struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
    3281056};
     1057
     1058/*
     1059  see if this getncchanges request includes a request to reveal secret information
     1060 */
     1061static WERROR dcesrv_drsuapi_is_reveal_secrets_request(struct drsuapi_bind_state *b_state,
     1062                                                       struct drsuapi_DsGetNCChangesRequest10 *req10,
     1063                                                       bool *is_secret_request)
     1064{
     1065        enum drsuapi_DsExtendedOperation exop;
     1066        uint32_t i;
     1067        struct dsdb_schema *schema;
     1068
     1069        *is_secret_request = true;
     1070
     1071        exop = req10->extended_op;
     1072
     1073        switch (exop) {
     1074        case DRSUAPI_EXOP_FSMO_REQ_ROLE:
     1075        case DRSUAPI_EXOP_FSMO_RID_ALLOC:
     1076        case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
     1077        case DRSUAPI_EXOP_FSMO_REQ_PDC:
     1078        case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
     1079                /* FSMO exops can reveal secrets */
     1080                *is_secret_request = true;
     1081                return WERR_OK;
     1082        case DRSUAPI_EXOP_REPL_SECRET:
     1083        case DRSUAPI_EXOP_REPL_OBJ:
     1084        case DRSUAPI_EXOP_NONE:
     1085                break;
     1086        }
     1087
     1088        if (req10->replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
     1089                *is_secret_request = false;
     1090                return WERR_OK;
     1091        }
     1092
     1093        if (exop == DRSUAPI_EXOP_REPL_SECRET ||
     1094            req10->partial_attribute_set == NULL) {
     1095                /* they want secrets */
     1096                *is_secret_request = true;
     1097                return WERR_OK;
     1098        }
     1099
     1100        schema = dsdb_get_schema(b_state->sam_ctx, NULL);
     1101
     1102        /* check the attributes they asked for */
     1103        for (i=0; i<req10->partial_attribute_set->num_attids; i++) {
     1104                const struct dsdb_attribute *sa;
     1105                sa = dsdb_attribute_by_attributeID_id(schema, req10->partial_attribute_set->attids[i]);
     1106                if (sa == NULL) {
     1107                        return WERR_DS_DRA_SCHEMA_MISMATCH;
     1108                }
     1109                if (!dsdb_attr_in_rodc_fas(sa)) {
     1110                        *is_secret_request = true;
     1111                        return WERR_OK;
     1112                }
     1113        }
     1114
     1115        /* check the attributes they asked for */
     1116        for (i=0; i<req10->partial_attribute_set_ex->num_attids; i++) {
     1117                const struct dsdb_attribute *sa;
     1118                sa = dsdb_attribute_by_attributeID_id(schema, req10->partial_attribute_set_ex->attids[i]);
     1119                if (sa == NULL) {
     1120                        return WERR_DS_DRA_SCHEMA_MISMATCH;
     1121                }
     1122                if (!dsdb_attr_in_rodc_fas(sa)) {
     1123                        *is_secret_request = true;
     1124                        return WERR_OK;
     1125                }
     1126        }
     1127
     1128        *is_secret_request = false;
     1129        return WERR_OK;
     1130}
     1131
     1132
     1133/*
     1134  map from req8 to req10
     1135 */
     1136static struct drsuapi_DsGetNCChangesRequest10 *
     1137getncchanges_map_req8(TALLOC_CTX *mem_ctx,
     1138                      struct drsuapi_DsGetNCChangesRequest8 *req8)
     1139{
     1140        struct drsuapi_DsGetNCChangesRequest10 *req10 = talloc_zero(mem_ctx,
     1141                                                                    struct drsuapi_DsGetNCChangesRequest10);
     1142        if (req10 == NULL) {
     1143                return NULL;
     1144        }
     1145
     1146        req10->destination_dsa_guid = req8->destination_dsa_guid;
     1147        req10->source_dsa_invocation_id = req8->source_dsa_invocation_id;
     1148        req10->naming_context = req8->naming_context;
     1149        req10->highwatermark = req8->highwatermark;
     1150        req10->uptodateness_vector = req8->uptodateness_vector;
     1151        req10->replica_flags = req8->replica_flags;
     1152        req10->max_object_count = req8->max_object_count;
     1153        req10->max_ndr_size = req8->max_ndr_size;
     1154        req10->extended_op = req8->extended_op;
     1155        req10->fsmo_info = req8->fsmo_info;
     1156        req10->partial_attribute_set = req8->partial_attribute_set;
     1157        req10->partial_attribute_set_ex = req8->partial_attribute_set_ex;
     1158        req10->mapping_ctr = req8->mapping_ctr;
     1159
     1160        return req10;
     1161}
     1162
    3291163
    3301164/*
    3311165  drsuapi_DsGetNCChanges
     1166
     1167  see MS-DRSR 4.1.10.5.2 for basic logic of this function
    3321168*/
    3331169WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     
    3361172        struct drsuapi_DsReplicaObjectIdentifier *ncRoot;
    3371173        int ret;
    338         int i;
     1174        uint32_t i;
    3391175        struct dsdb_schema *schema;
    3401176        struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
     
    3421178        NTSTATUS status;
    3431179        DATA_BLOB session_key;
    344         const char *attrs[] = { "*", "distinguishedName", NULL };
     1180        const char *attrs[] = { "uSNChanged",
     1181                                "objectGUID" ,
     1182                                NULL };
    3451183        WERROR werr;
    3461184        struct dcesrv_handle *h;
    3471185        struct drsuapi_bind_state *b_state;     
    3481186        struct drsuapi_getncchanges_state *getnc_state;
     1187        struct drsuapi_DsGetNCChangesRequest10 *req10;
     1188        uint32_t options;
     1189        uint32_t max_objects;
     1190        uint32_t max_links;
     1191        uint32_t link_count = 0;
     1192        uint32_t link_total = 0;
     1193        uint32_t link_given = 0;
     1194        struct ldb_dn *search_dn = NULL;
     1195        bool am_rodc, null_scope=false;
     1196        enum security_user_level security_level;
     1197        struct ldb_context *sam_ctx;
     1198        struct dom_sid *user_sid;
     1199        bool is_secret_request;
    3491200
    3501201        DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
    3511202        b_state = h->data;
     1203
     1204        sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
    3521205
    3531206        *r->out.level_out = 6;
     
    3611214        r->out.ctr->ctr6.uptodateness_vector = NULL;
    3621215
    363         /* Check request revision. */
    364         if (r->in.level != 8) {
     1216        /* a RODC doesn't allow for any replication */
     1217        ret = samdb_rodc(sam_ctx, &am_rodc);
     1218        if (ret == LDB_SUCCESS && am_rodc) {
     1219                DEBUG(0,(__location__ ": DsGetNCChanges attempt on RODC\n"));
     1220                return WERR_DS_DRA_SOURCE_DISABLED;
     1221        }
     1222
     1223        /* Check request revision.
     1224         */
     1225        switch (r->in.level) {
     1226        case 8:
     1227                req10 = getncchanges_map_req8(mem_ctx, &r->in.req->req8);
     1228                if (req10 == NULL) {
     1229                        return WERR_NOMEM;
     1230                }
     1231                break;
     1232        case 10:
     1233                req10 = &r->in.req->req10;
     1234                break;
     1235        default:
     1236                DEBUG(0,(__location__ ": Request for DsGetNCChanges with unsupported level %u\n",
     1237                         r->in.level));
    3651238                return WERR_REVISION_MISMATCH;
    3661239        }
    3671240
     1241
    3681242        /* Perform access checks. */
    369         if (r->in.req->req8.naming_context == NULL) {
     1243        /* TODO: we need to support a sync on a specific non-root
     1244         * DN. We'll need to find the real partition root here */
     1245        ncRoot = req10->naming_context;
     1246        if (ncRoot == NULL) {
     1247                DEBUG(0,(__location__ ": Request for DsGetNCChanges with no NC\n"));
    3701248                return WERR_DS_DRA_INVALID_PARAMETER;
    3711249        }
    3721250
    373         ncRoot = r->in.req->req8.naming_context;
    374         if (ncRoot == NULL) {
    375                 return WERR_DS_DRA_BAD_NC;
    376         }
    377 
    378         if ((r->in.req->req8.replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_SYNC_PACKET)
    379             == DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_SYNC_PACKET) {
    380                 /* Ignore the _in_ uptpdateness vector*/
    381                 r->in.req->req8.uptodateness_vector = NULL;
    382         }
    383 
    384         werr = drs_security_level_check(dce_call, "DsGetNCChanges");
     1251        if (samdb_ntds_options(sam_ctx, &options) != LDB_SUCCESS) {
     1252                return WERR_DS_DRA_INTERNAL_ERROR;
     1253        }
     1254       
     1255        if ((options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) &&
     1256            !(req10->replica_flags & DRSUAPI_DRS_SYNC_FORCED)) {
     1257                return WERR_DS_DRA_SOURCE_DISABLED;
     1258        }
     1259
     1260        user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
     1261
     1262        werr = drs_security_access_check_nc_root(b_state->sam_ctx,
     1263                                                 mem_ctx,
     1264                                                 dce_call->conn->auth_state.session_info->security_token,
     1265                                                 req10->naming_context,
     1266                                                 GUID_DRS_GET_CHANGES);
    3851267        if (!W_ERROR_IS_OK(werr)) {
    3861268                return werr;
    3871269        }
    3881270
     1271        werr = dcesrv_drsuapi_is_reveal_secrets_request(b_state, req10, &is_secret_request);
     1272        if (!W_ERROR_IS_OK(werr)) {
     1273                return werr;
     1274        }
     1275        if (is_secret_request && req10->extended_op != DRSUAPI_EXOP_REPL_SECRET) {
     1276                werr = drs_security_access_check_nc_root(b_state->sam_ctx,
     1277                                                         mem_ctx,
     1278                                                         dce_call->conn->auth_state.session_info->security_token,
     1279                                                         req10->naming_context,
     1280                                                         GUID_DRS_GET_ALL_CHANGES);
     1281                if (!W_ERROR_IS_OK(werr)) {
     1282                        return werr;
     1283                }
     1284        }
     1285
     1286        /* for non-administrator replications, check that they have
     1287           given the correct source_dsa_invocation_id */
     1288        security_level = security_session_user_level(dce_call->conn->auth_state.session_info,
     1289                                                     samdb_domain_sid(sam_ctx));
     1290        if (security_level == SECURITY_RO_DOMAIN_CONTROLLER) {
     1291                if (req10->replica_flags & DRSUAPI_DRS_WRIT_REP) {
     1292                        /* we rely on this flag being unset for RODC requests */
     1293                        req10->replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
     1294                }
     1295        }
     1296
     1297        if (req10->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) {
     1298                /* Ignore the _in_ uptpdateness vector*/
     1299                req10->uptodateness_vector = NULL;
     1300        }
     1301
    3891302        getnc_state = b_state->getncchanges_state;
     1303
     1304        /* see if a previous replication has been abandoned */
     1305        if (getnc_state) {
     1306                struct ldb_dn *new_dn = drs_ObjectIdentifier_to_dn(getnc_state, sam_ctx, ncRoot);
     1307                if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) {
     1308                        DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n",
     1309                                 ldb_dn_get_linearized(new_dn),
     1310                                 ldb_dn_get_linearized(getnc_state->ncRoot_dn),
     1311                                 ldb_dn_get_linearized(getnc_state->last_dn)));
     1312                        talloc_free(getnc_state);
     1313                        getnc_state = NULL;
     1314                }
     1315        }
     1316
    3901317        if (getnc_state == NULL) {
    3911318                getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
     
    3941321                }
    3951322                b_state->getncchanges_state = getnc_state;
    396 
     1323                getnc_state->ncRoot_dn = drs_ObjectIdentifier_to_dn(getnc_state, sam_ctx, ncRoot);
     1324
     1325                /* find out if we are to replicate Schema NC */
     1326                ret = ldb_dn_compare(getnc_state->ncRoot_dn,
     1327                                     ldb_get_schema_basedn(b_state->sam_ctx));
     1328                getnc_state->is_schema_nc = (0 == ret);
    3971329
    3981330                /*
    399                  * connect to the samdb. TODO: We need to check that the caller
    400                  * has the rights to do this. This exposes all attributes,
    401                  * including all passwords.
     1331                 * This is the first replication cycle and it is
     1332                 * a good place to handle extended operations
     1333                 *
     1334                 * FIXME: we don't fully support extended operations yet
    4021335                 */
    403                 getnc_state->sam_ctx = samdb_connect(getnc_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
    404                                                      system_session(getnc_state, dce_call->conn->dce_ctx->lp_ctx));
    405                 if (!getnc_state->sam_ctx) {
    406                         return WERR_FOOBAR;
    407                 }
     1336                switch (req10->extended_op) {
     1337                case DRSUAPI_EXOP_NONE:
     1338                        break;
     1339                case DRSUAPI_EXOP_FSMO_RID_ALLOC:
     1340                        werr = getncchanges_rid_alloc(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
     1341                        W_ERROR_NOT_OK_RETURN(werr);
     1342                        search_dn = ldb_get_default_basedn(sam_ctx);
     1343                        break;
     1344                case DRSUAPI_EXOP_REPL_SECRET:
     1345                        werr = getncchanges_repl_secret(b_state, mem_ctx, req10, user_sid, &r->out.ctr->ctr6);
     1346                        r->out.result = werr;
     1347                        W_ERROR_NOT_OK_RETURN(werr);
     1348                        break;
     1349                case DRSUAPI_EXOP_FSMO_REQ_ROLE:
     1350                        werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
     1351                        W_ERROR_NOT_OK_RETURN(werr);
     1352                        break;
     1353                case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
     1354                        werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
     1355                        W_ERROR_NOT_OK_RETURN(werr);
     1356                        break;
     1357                case DRSUAPI_EXOP_FSMO_REQ_PDC:
     1358                        werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
     1359                        W_ERROR_NOT_OK_RETURN(werr);
     1360                        break;
     1361                case DRSUAPI_EXOP_REPL_OBJ:
     1362                        werr = getncchanges_repl_obj(b_state, mem_ctx, req10, user_sid, &r->out.ctr->ctr6);
     1363                        r->out.result = werr;
     1364                        W_ERROR_NOT_OK_RETURN(werr);
     1365                        break;
     1366
     1367                case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
     1368
     1369                        DEBUG(0,(__location__ ": Request for DsGetNCChanges unsupported extended op 0x%x\n",
     1370                                 (unsigned)req10->extended_op));
     1371                        return WERR_DS_DRA_NOT_SUPPORTED;
     1372                }
     1373        }
     1374
     1375        if (!ldb_dn_validate(getnc_state->ncRoot_dn) ||
     1376            ldb_dn_is_null(getnc_state->ncRoot_dn)) {
     1377                DEBUG(0,(__location__ ": Bad DN '%s'\n",
     1378                         drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
     1379                return WERR_DS_DRA_INVALID_PARAMETER;
    4081380        }
    4091381
     
    4151387        }
    4161388
    417         if (getnc_state->site_res == NULL) {
     1389        /*
     1390           TODO: MS-DRSR section 4.1.10.1.1
     1391           Work out if this is the start of a new cycle */
     1392
     1393        if (getnc_state->guids == NULL) {
    4181394                char* search_filter;
    4191395                enum ldb_scope scope = LDB_SCOPE_SUBTREE;
    420 
    421                 getnc_state->min_usn = r->in.req->req8.highwatermark.highest_usn;
     1396                const char *extra_filter;
     1397                struct ldb_result *search_res;
     1398
     1399                if (req10->extended_op == DRSUAPI_EXOP_REPL_OBJ ||
     1400                    req10->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
     1401                        scope = LDB_SCOPE_BASE;
     1402                }
     1403
     1404                extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
     1405
     1406                getnc_state->min_usn = req10->highwatermark.highest_usn;
    4221407
    4231408                /* Construct response. */
     
    4251410                                                "(uSNChanged>=%llu)",
    4261411                                                (unsigned long long)(getnc_state->min_usn+1));
    427                
    428                 if (r->in.req->req8.replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_CRITICAL_ONLY) {
     1412       
     1413                if (extra_filter) {
     1414                        search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter);
     1415                }
     1416
     1417                if (req10->replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
    4291418                        search_filter = talloc_asprintf(mem_ctx,
    4301419                                                        "(&%s(isCriticalSystemObject=TRUE))",
     
    4321421                }
    4331422               
    434                 getnc_state->ncRoot_dn = ldb_dn_new(getnc_state, getnc_state->sam_ctx, ncRoot->dn);
    435                 if (r->in.req->req8.replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_ASYNC_REP) {
     1423                if (req10->replica_flags & DRSUAPI_DRS_ASYNC_REP) {
    4361424                        scope = LDB_SCOPE_BASE;
    4371425                }
    4381426               
    439                 DEBUG(6,(__location__ ": getncchanges on %s using filter %s\n",
     1427                if (!search_dn) {
     1428                        search_dn = getnc_state->ncRoot_dn;
     1429                }
     1430
     1431                DEBUG(2,(__location__ ": getncchanges on %s using filter %s\n",
    4401432                         ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter));
    441                 ret = drsuapi_search_with_extended_dn(getnc_state->sam_ctx, getnc_state, &getnc_state->site_res,
    442                                                       getnc_state->ncRoot_dn, scope, attrs,
    443                                                       "distinguishedName",
     1433                ret = drsuapi_search_with_extended_dn(sam_ctx, getnc_state, &search_res,
     1434                                                      search_dn, scope, attrs,
    4441435                                                      search_filter);
    4451436                if (ret != LDB_SUCCESS) {
    4461437                        return WERR_DS_DRA_INTERNAL_ERROR;
    4471438                }
     1439
     1440                if (req10->replica_flags & DRSUAPI_DRS_GET_ANC) {
     1441                        TYPESAFE_QSORT(search_res->msgs,
     1442                                       search_res->count,
     1443                                       site_res_cmp_parent_order);
     1444                } else {
     1445                        TYPESAFE_QSORT(search_res->msgs,
     1446                                       search_res->count,
     1447                                       site_res_cmp_usn_order);
     1448                }
     1449
     1450                /* extract out the GUIDs list */
     1451                getnc_state->num_records = search_res->count;
     1452                getnc_state->guids = talloc_array(getnc_state, struct GUID, getnc_state->num_records);
     1453                W_ERROR_HAVE_NO_MEMORY(getnc_state->guids);
     1454
     1455                for (i=0; i<getnc_state->num_records; i++) {
     1456                        getnc_state->guids[i] = samdb_result_guid(search_res->msgs[i], "objectGUID");
     1457                        if (GUID_all_zero(&getnc_state->guids[i])) {
     1458                                DEBUG(2,("getncchanges: bad objectGUID from %s\n", ldb_dn_get_linearized(search_res->msgs[i]->dn)));
     1459                                return WERR_DS_DRA_INTERNAL_ERROR;
     1460                        }
     1461                }
     1462
     1463
     1464                talloc_free(search_res);
     1465
     1466                getnc_state->uptodateness_vector = talloc_steal(getnc_state, req10->uptodateness_vector);
     1467                if (getnc_state->uptodateness_vector) {
     1468                        /* make sure its sorted */
     1469                        TYPESAFE_QSORT(getnc_state->uptodateness_vector->cursors,
     1470                                       getnc_state->uptodateness_vector->count,
     1471                                       drsuapi_DsReplicaCursor_compare);
     1472                }
    4481473        }
    4491474
    4501475        /* Prefix mapping */
    451         schema = dsdb_get_schema(getnc_state->sam_ctx);
     1476        schema = dsdb_get_schema(sam_ctx, mem_ctx);
    4521477        if (!schema) {
    4531478                DEBUG(0,("No schema in sam_ctx\n"));
     
    4581483        *r->out.ctr->ctr6.naming_context = *ncRoot;
    4591484
    460         if (dsdb_find_guid_by_dn(getnc_state->sam_ctx, getnc_state->ncRoot_dn,
     1485        if (dsdb_find_guid_by_dn(sam_ctx, getnc_state->ncRoot_dn,
    4611486                                 &r->out.ctr->ctr6.naming_context->guid) != LDB_SUCCESS) {
    4621487                DEBUG(0,(__location__ ": Failed to find GUID of ncRoot_dn %s\n",
     
    4661491
    4671492        /* find the SID if there is one */
    468         dsdb_find_sid_by_dn(getnc_state->sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
     1493        dsdb_find_sid_by_dn(sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
    4691494
    4701495        dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, &ctr);
    4711496        r->out.ctr->ctr6.mapping_ctr = *ctr;
    4721497
    473         r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(getnc_state->sam_ctx));
    474         r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(getnc_state->sam_ctx));
    475 
    476         r->out.ctr->ctr6.old_highwatermark = r->in.req->req8.highwatermark;
    477         r->out.ctr->ctr6.new_highwatermark = r->in.req->req8.highwatermark;
     1498        r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(sam_ctx));
     1499        r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
     1500
     1501        r->out.ctr->ctr6.old_highwatermark = req10->highwatermark;
     1502        r->out.ctr->ctr6.new_highwatermark = req10->highwatermark;
    4781503
    4791504        r->out.ctr->ctr6.first_object = NULL;
    4801505        currentObject = &r->out.ctr->ctr6.first_object;
    4811506
    482         for(i=getnc_state->num_sent;
    483             i<getnc_state->site_res->count &&
    484                     (r->out.ctr->ctr6.object_count < r->in.req->req8.max_object_count);
     1507        /* use this to force single objects at a time, which is useful
     1508         * for working out what object is giving problems
     1509         */
     1510        max_objects = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max object sync", 1000);
     1511        if (req10->max_object_count < max_objects) {
     1512                max_objects = req10->max_object_count;
     1513        }
     1514        /*
     1515         * TODO: work out how the maximum should be calculated
     1516         */
     1517        max_links = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max link sync", 1500);
     1518
     1519        for (i=getnc_state->num_processed;
     1520             i<getnc_state->num_records &&
     1521                     !null_scope &&
     1522                     (r->out.ctr->ctr6.object_count < max_objects);
    4851523            i++) {
    4861524                int uSN;
    4871525                struct drsuapi_DsReplicaObjectListItemEx *obj;
     1526                struct ldb_message *msg;
     1527                static const char * const msg_attrs[] = {
     1528                                            "*",
     1529                                            "nTSecurityDescriptor",
     1530                                            "parentGUID",
     1531                                            "replPropertyMetaData",
     1532                                            DSDB_SECRET_ATTRIBUTES,
     1533                                            NULL };
     1534                struct ldb_result *msg_res;
     1535                struct ldb_dn *msg_dn;
     1536
    4881537                obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx);
    489 
    490                 uSN = ldb_msg_find_attr_as_int(getnc_state->site_res->msgs[i], "uSNChanged", -1);
     1538                W_ERROR_HAVE_NO_MEMORY(obj);
     1539
     1540                msg_dn = ldb_dn_new_fmt(obj, sam_ctx, "<GUID=%s>", GUID_string(obj, &getnc_state->guids[i]));
     1541                W_ERROR_HAVE_NO_MEMORY(msg_dn);
     1542
     1543
     1544                /* by re-searching here we avoid having a lot of full
     1545                 * records in memory between calls to getncchanges
     1546                 */
     1547                ret = drsuapi_search_with_extended_dn(sam_ctx, obj, &msg_res,
     1548                                                      msg_dn,
     1549                                                      LDB_SCOPE_BASE, msg_attrs, NULL);
     1550                if (ret != LDB_SUCCESS) {
     1551                        if (ret != LDB_ERR_NO_SUCH_OBJECT) {
     1552                                DEBUG(1,("getncchanges: failed to fetch DN %s - %s\n",
     1553                                         ldb_dn_get_extended_linearized(obj, msg_dn, 1), ldb_errstring(sam_ctx)));
     1554                        }
     1555                        talloc_free(obj);
     1556                        continue;
     1557                }
     1558
     1559                msg = msg_res->msgs[0];
     1560
     1561                werr = get_nc_changes_build_object(obj, msg,
     1562                                                   sam_ctx, getnc_state->ncRoot_dn,
     1563                                                   getnc_state->is_schema_nc,
     1564                                                   schema, &session_key, getnc_state->min_usn,
     1565                                                   req10->replica_flags,
     1566                                                   req10->partial_attribute_set,
     1567                                                   getnc_state->uptodateness_vector,
     1568                                                   req10->extended_op);
     1569                if (!W_ERROR_IS_OK(werr)) {
     1570                        return werr;
     1571                }
     1572
     1573                werr = get_nc_changes_add_links(sam_ctx, getnc_state,
     1574                                                getnc_state->ncRoot_dn,
     1575                                                schema, getnc_state->min_usn,
     1576                                                req10->replica_flags,
     1577                                                msg,
     1578                                                &getnc_state->la_list,
     1579                                                &getnc_state->la_count,
     1580                                                getnc_state->uptodateness_vector);
     1581                if (!W_ERROR_IS_OK(werr)) {
     1582                        return werr;
     1583                }
     1584
     1585                uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1);
    4911586                if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) {
    4921587                        r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN;
    4931588                }
    494 
    495                 werr = get_nc_changes_build_object(obj, getnc_state->site_res->msgs[i],
    496                                                    getnc_state->sam_ctx, getnc_state->ncRoot_dn,
    497                                                    schema, &session_key, getnc_state->min_usn,
    498                                                    r->in.req->req8.replica_flags);
    499                 if (!W_ERROR_IS_OK(werr)) {
    500                         return werr;
     1589                if (uSN > getnc_state->highest_usn) {
     1590                        getnc_state->highest_usn = uSN;
    5011591                }
    5021592
    5031593                if (obj->meta_data_ctr == NULL) {
    504                         DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n",
    505                                  ldb_dn_get_linearized(getnc_state->site_res->msgs[i]->dn)));
     1594                        DEBUG(8,(__location__ ": getncchanges skipping send of object %s\n",
     1595                                 ldb_dn_get_linearized(msg->dn)));
    5061596                        /* no attributes to send */
    5071597                        talloc_free(obj);
     
    5131603                *currentObject = obj;
    5141604                currentObject = &obj->next_object;
    515         }
    516 
    517         getnc_state->num_sent += r->out.ctr->ctr6.object_count;
    518 
    519         r->out.ctr->ctr6.nc_object_count = getnc_state->site_res->count;
    520 
    521         if (i < getnc_state->site_res->count) {
     1605
     1606                talloc_free(getnc_state->last_dn);
     1607                getnc_state->last_dn = ldb_dn_copy(getnc_state, msg->dn);
     1608
     1609                DEBUG(8,(__location__ ": replicating object %s\n", ldb_dn_get_linearized(msg->dn)));
     1610
     1611                talloc_free(msg_res);
     1612                talloc_free(msg_dn);
     1613        }
     1614
     1615        getnc_state->num_processed = i;
     1616
     1617        r->out.ctr->ctr6.nc_object_count = getnc_state->num_records;
     1618
     1619        /* the client can us to call UpdateRefs on its behalf to
     1620           re-establish monitoring of the NC */
     1621        if ((req10->replica_flags & (DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_REF_GCSPN)) &&
     1622            !GUID_all_zero(&req10->destination_dsa_guid)) {
     1623                struct drsuapi_DsReplicaUpdateRefsRequest1 ureq;
     1624                DEBUG(3,("UpdateRefs on getncchanges for %s\n",
     1625                         GUID_string(mem_ctx, &req10->destination_dsa_guid)));
     1626                ureq.naming_context = ncRoot;
     1627                ureq.dest_dsa_dns_name = talloc_asprintf(mem_ctx, "%s._msdcs.%s",
     1628                                                         GUID_string(mem_ctx, &req10->destination_dsa_guid),
     1629                                                         lpcfg_dnsdomain(dce_call->conn->dce_ctx->lp_ctx));
     1630                if (!ureq.dest_dsa_dns_name) {
     1631                        return WERR_NOMEM;
     1632                }
     1633                ureq.dest_dsa_guid = req10->destination_dsa_guid;
     1634                ureq.options = DRSUAPI_DRS_ADD_REF |
     1635                        DRSUAPI_DRS_ASYNC_OP |
     1636                        DRSUAPI_DRS_GETCHG_CHECK;
     1637
     1638                /* we also need to pass through the
     1639                   DRSUAPI_DRS_REF_GCSPN bit so that repsTo gets flagged
     1640                   to send notifies using the GC SPN */
     1641                ureq.options |= (req10->replica_flags & DRSUAPI_DRS_REF_GCSPN);
     1642
     1643                werr = drsuapi_UpdateRefs(b_state, mem_ctx, &ureq);
     1644                if (!W_ERROR_IS_OK(werr)) {
     1645                        DEBUG(0,(__location__ ": Failed UpdateRefs in DsGetNCChanges - %s\n",
     1646                                 win_errstr(werr)));
     1647                }
     1648        }
     1649
     1650        /*
     1651         * TODO:
     1652         * This is just a guess, how to calculate the
     1653         * number of linked attributes to send, we need to
     1654         * find out how to do this right.
     1655         */
     1656        if (r->out.ctr->ctr6.object_count >= max_links) {
     1657                max_links = 0;
     1658        } else {
     1659                max_links -= r->out.ctr->ctr6.object_count;
     1660        }
     1661
     1662        link_total = getnc_state->la_count;
     1663
     1664        if (i < getnc_state->num_records) {
    5221665                r->out.ctr->ctr6.more_data = true;
    5231666        } else {
     1667                /* sort the whole array the first time */
     1668                if (!getnc_state->la_sorted) {
     1669                        LDB_TYPESAFE_QSORT(getnc_state->la_list, getnc_state->la_count,
     1670                                           sam_ctx, linked_attribute_compare);
     1671                        getnc_state->la_sorted = true;
     1672                }
     1673
     1674                link_count = getnc_state->la_count - getnc_state->la_idx;
     1675                link_count = MIN(max_links, link_count);
     1676
     1677                r->out.ctr->ctr6.linked_attributes_count = link_count;
     1678                r->out.ctr->ctr6.linked_attributes = getnc_state->la_list + getnc_state->la_idx;
     1679
     1680                getnc_state->la_idx += link_count;
     1681                link_given = getnc_state->la_idx;
     1682
     1683                if (getnc_state->la_idx < getnc_state->la_count) {
     1684                        r->out.ctr->ctr6.more_data = true;
     1685                }
     1686        }
     1687
     1688        if (!r->out.ctr->ctr6.more_data) {
     1689                talloc_steal(mem_ctx, getnc_state->la_list);
     1690
    5241691                r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx);
    525                 r->out.ctr->ctr6.uptodateness_vector->version = 2;
    526                 r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0;
    527                 r->out.ctr->ctr6.uptodateness_vector->reserved2 = 0;
    528 
    5291692                r->out.ctr->ctr6.new_highwatermark.highest_usn = r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn;
    5301693
    531                 werr = get_nc_changes_udv(getnc_state->sam_ctx, getnc_state->ncRoot_dn,
     1694                werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn,
    5321695                                          r->out.ctr->ctr6.uptodateness_vector);
    5331696                if (!W_ERROR_IS_OK(werr)) {
     
    5391702        }
    5401703
    541         DEBUG(3,("DsGetNCChanges with uSNChanged >= %llu on %s gave %u objects\n",
    542                  (unsigned long long)(r->in.req->req8.highwatermark.highest_usn+1),
    543                  ncRoot->dn, r->out.ctr->ctr6.object_count));
     1704        if (req10->extended_op != DRSUAPI_EXOP_NONE) {
     1705                r->out.ctr->ctr6.uptodateness_vector = NULL;
     1706                r->out.ctr->ctr6.nc_object_count = 0;
     1707                ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark);
     1708                r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
     1709        }
     1710
     1711        DEBUG(r->out.ctr->ctr6.more_data?4:2,
     1712              ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %u/%u) %u links (done %u/%u (as %s))\n",
     1713               (unsigned long long)(req10->highwatermark.highest_usn+1),
     1714               req10->replica_flags, drs_ObjectIdentifier_to_string(mem_ctx, ncRoot),
     1715               r->out.ctr->ctr6.object_count,
     1716               i, r->out.ctr->ctr6.more_data?getnc_state->num_records:i,
     1717               r->out.ctr->ctr6.linked_attributes_count,
     1718               link_given, link_total,
     1719               dom_sid_string(mem_ctx, user_sid)));
     1720
     1721#if 0
     1722        if (!r->out.ctr->ctr6.more_data && req10->extended_op != DRSUAPI_EXOP_NONE) {
     1723                NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsGetNCChanges, NDR_BOTH, r);
     1724        }
     1725#endif
    5441726
    5451727        return WERR_OK;
  • trunk/server/source4/rpc_server/drsuapi/updaterefs.c

    r414 r745  
    2323#include "rpc_server/dcerpc_server.h"
    2424#include "dsdb/samdb/samdb.h"
    25 #include "auth/auth.h"
     25#include "libcli/security/security.h"
     26#include "libcli/security/session.h"
    2627#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
    27 #include "libcli/security/security.h"
     28#include "auth/session.h"
     29#include "librpc/gen_ndr/ndr_drsuapi.h"
    2830
    2931struct repsTo {
     
    3638 */
    3739static WERROR uref_add_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    38                             struct ldb_dn *dn, struct repsFromTo1 *dest)
     40                            struct ldb_dn *dn, struct repsFromTo1 *dest,
     41                            uint32_t options)
    3942{
    4043        struct repsTo reps;
    4144        WERROR werr;
     45        unsigned int i;
    4246
    4347        werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count);
    4448        if (!W_ERROR_IS_OK(werr)) {
    4549                return werr;
     50        }
     51
     52        for (i=0; i<reps.count; i++) {
     53                if (GUID_compare(&dest->source_dsa_obj_guid,
     54                                 &reps.r[i].ctr.ctr1.source_dsa_obj_guid) == 0) {
     55                        if (options & DRSUAPI_DRS_GETCHG_CHECK) {
     56                                return WERR_OK;
     57                        } else {
     58                                return WERR_DS_DRA_REF_ALREADY_EXISTS;
     59                        }
     60                }
    4661        }
    4762
     
    5368        reps.r[reps.count].version = 1;
    5469        reps.r[reps.count].ctr.ctr1 = *dest;
     70        /* add the GCSPN flag if the client asked for it */
     71        reps.r[reps.count].ctr.ctr1.replica_flags |= (options & DRSUAPI_DRS_REF_GCSPN);
    5572        reps.count++;
    5673
     
    6784 */
    6885static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    69                             struct ldb_dn *dn, struct GUID *dest_guid)
     86                            struct ldb_dn *dn, struct GUID *dest_guid,
     87                            uint32_t options)
    7088{
    7189        struct repsTo reps;
    7290        WERROR werr;
    73         int i;
     91        unsigned int i;
     92        bool found = false;
    7493
    7594        werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count);
     
    84103                        }
    85104                        reps.count--;
     105                        found = true;
    86106                }
    87107        }
     
    92112        }
    93113
     114        if (!found &&
     115            !(options & DRSUAPI_DRS_GETCHG_CHECK) &&
     116            !(options & DRSUAPI_DRS_ADD_REF)) {
     117                return WERR_DS_DRA_REF_NOT_FOUND;
     118        }
     119
    94120        return WERR_OK;
     121}
     122
     123/*
     124  drsuapi_DsReplicaUpdateRefs - a non RPC version callable from getncchanges
     125*/
     126WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
     127                          struct drsuapi_DsReplicaUpdateRefsRequest1 *req)
     128{
     129        WERROR werr;
     130        struct ldb_dn *dn;
     131        struct ldb_context *sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
     132
     133        DEBUG(4,("DsReplicaUpdateRefs for host '%s' with GUID %s options 0x%08x nc=%s\n",
     134                 req->dest_dsa_dns_name, GUID_string(mem_ctx, &req->dest_dsa_guid),
     135                 req->options,
     136                 drs_ObjectIdentifier_to_string(mem_ctx, req->naming_context)));
     137
     138        dn = ldb_dn_new(mem_ctx, sam_ctx, req->naming_context->dn);
     139        if (dn == NULL) {
     140                return WERR_DS_INVALID_DN_SYNTAX;
     141        }
     142
     143        if (ldb_transaction_start(sam_ctx) != LDB_SUCCESS) {
     144                DEBUG(0,(__location__ ": Failed to start transaction on samdb: %s\n",
     145                         ldb_errstring(sam_ctx)));
     146                return WERR_DS_DRA_INTERNAL_ERROR;             
     147        }
     148
     149        if (req->options & DRSUAPI_DRS_DEL_REF) {
     150                werr = uref_del_dest(sam_ctx, mem_ctx, dn, &req->dest_dsa_guid, req->options);
     151                if (!W_ERROR_IS_OK(werr)) {
     152                        DEBUG(0,("Failed to delete repsTo for %s: %s\n",
     153                                 GUID_string(mem_ctx, &req->dest_dsa_guid),
     154                                 win_errstr(werr)));
     155                        goto failed;
     156                }
     157        }
     158
     159        if (req->options & DRSUAPI_DRS_ADD_REF) {
     160                struct repsFromTo1 dest;
     161                struct repsFromTo1OtherInfo oi;
     162               
     163                ZERO_STRUCT(dest);
     164                ZERO_STRUCT(oi);
     165
     166                oi.dns_name = req->dest_dsa_dns_name;
     167                dest.other_info          = &oi;
     168                dest.source_dsa_obj_guid = req->dest_dsa_guid;
     169                dest.replica_flags       = req->options;
     170
     171                werr = uref_add_dest(sam_ctx, mem_ctx, dn, &dest, req->options);
     172                if (!W_ERROR_IS_OK(werr)) {
     173                        DEBUG(0,("Failed to add repsTo for %s: %s\n",
     174                                 GUID_string(mem_ctx, &dest.source_dsa_obj_guid),
     175                                 win_errstr(werr)));
     176                        goto failed;
     177                }
     178        }
     179
     180        if (ldb_transaction_commit(sam_ctx) != LDB_SUCCESS) {
     181                DEBUG(0,(__location__ ": Failed to commit transaction on samdb: %s\n",
     182                         ldb_errstring(sam_ctx)));
     183                return WERR_DS_DRA_INTERNAL_ERROR;             
     184        }
     185
     186        return WERR_OK;
     187
     188failed:
     189        ldb_transaction_cancel(sam_ctx);
     190        return werr;
    95191}
    96192
     
    101197                                          struct drsuapi_DsReplicaUpdateRefs *r)
    102198{
     199        struct dcesrv_handle *h;
     200        struct drsuapi_bind_state *b_state;
    103201        struct drsuapi_DsReplicaUpdateRefsRequest1 *req;
    104         struct ldb_context *sam_ctx;
    105         WERROR werr;
    106         struct ldb_dn *dn;
    107 
    108         werr = drs_security_level_check(dce_call, "DsReplicaUpdateRefs");
    109         if (!W_ERROR_IS_OK(werr)) {
    110                 return werr;
    111         }
     202        WERROR werr;
     203        int ret;
     204        enum security_user_level security_level;
     205
     206        DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
     207        b_state = h->data;
    112208
    113209        if (r->in.level != 1) {
     
    115211                return WERR_DS_DRA_INVALID_PARAMETER;
    116212        }
    117 
    118213        req = &r->in.req.req1;
    119         DEBUG(4,("DsReplicaUpdateRefs for host '%s' with GUID %s options 0x%08x nc=%s\n",
    120                  req->dest_dsa_dns_name, GUID_string(mem_ctx, &req->dest_dsa_guid),
    121                  req->options,
    122                  drs_ObjectIdentifier_to_string(mem_ctx, req->naming_context)));
    123 
    124         /* TODO: We need to authenticate this operation pretty carefully */
    125         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
    126                                 system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
    127         if (!sam_ctx) {
    128                 return WERR_DS_DRA_INTERNAL_ERROR;             
    129         }
    130 
    131         dn = ldb_dn_new(mem_ctx, sam_ctx, req->naming_context->dn);
    132         if (dn == NULL) {
    133                 talloc_free(sam_ctx);           
    134                 return WERR_DS_INVALID_DN_SYNTAX;
    135         }
    136 
    137         if (ldb_transaction_start(sam_ctx) != LDB_SUCCESS) {
    138                 DEBUG(0,(__location__ ": Failed to start transaction on samdb\n"));
    139                 talloc_free(sam_ctx);
    140                 return WERR_DS_DRA_INTERNAL_ERROR;             
    141         }
    142 
    143         if (req->options & DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE) {
    144                 werr = uref_del_dest(sam_ctx, mem_ctx, dn, &req->dest_dsa_guid);
    145                 if (!W_ERROR_IS_OK(werr)) {
    146                         DEBUG(0,("Failed to delete repsTo for %s\n",
    147                                  GUID_string(dce_call, &req->dest_dsa_guid)));
    148                         goto failed;
    149                 }
    150         }
    151 
    152         if (req->options & DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE) {
    153                 struct repsFromTo1 dest;
    154                 struct repsFromTo1OtherInfo oi;
    155                
    156                 ZERO_STRUCT(dest);
    157                 ZERO_STRUCT(oi);
    158 
    159                 oi.dns_name = req->dest_dsa_dns_name;
    160                 dest.other_info          = &oi;
    161                 dest.source_dsa_obj_guid = req->dest_dsa_guid;
    162                 dest.replica_flags       = req->options;
    163 
    164                 werr = uref_add_dest(sam_ctx, mem_ctx, dn, &dest);
    165                 if (!W_ERROR_IS_OK(werr)) {
    166                         DEBUG(0,("Failed to delete repsTo for %s\n",
    167                                  GUID_string(dce_call, &dest.source_dsa_obj_guid)));
    168                         goto failed;
    169                 }
    170         }
    171 
    172         if (ldb_transaction_commit(sam_ctx) != LDB_SUCCESS) {
    173                 DEBUG(0,(__location__ ": Failed to commit transaction on samdb\n"));
    174                 return WERR_DS_DRA_INTERNAL_ERROR;             
    175         }
    176 
    177         talloc_free(sam_ctx);
    178         return WERR_OK;
    179 
    180 failed:
    181         ldb_transaction_cancel(sam_ctx);
    182         talloc_free(sam_ctx);
     214        werr = drs_security_access_check(b_state->sam_ctx,
     215                                         mem_ctx,
     216                                         dce_call->conn->auth_state.session_info->security_token,
     217                                         req->naming_context,
     218                                         GUID_DRS_MANAGE_TOPOLOGY);
     219
     220        if (!W_ERROR_IS_OK(werr)) {
     221                return werr;
     222        }
     223
     224        security_level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
     225        if (security_level < SECURITY_ADMINISTRATOR) {
     226                /* check that they are using an DSA objectGUID that they own */
     227                ret = dsdb_validate_dsa_guid(b_state->sam_ctx,
     228                                             &req->dest_dsa_guid,
     229                                             &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]);
     230                if (ret != LDB_SUCCESS) {
     231                        DEBUG(0,(__location__ ": Refusing DsReplicaUpdateRefs for sid %s with GUID %s\n",
     232                                 dom_sid_string(mem_ctx,
     233                                                &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]),
     234                                 GUID_string(mem_ctx, &req->dest_dsa_guid)));
     235                        return WERR_DS_DRA_ACCESS_DENIED;
     236                }
     237        }
     238
     239        werr = drsuapi_UpdateRefs(b_state, mem_ctx, req);
     240
     241#if 0
     242        NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsReplicaUpdateRefs, NDR_BOTH, r);
     243#endif
     244
    183245        return werr;
    184246}
Note: See TracChangeset for help on using the changeset viewer.