s3/torture: local_rbtree: avoid birthday collisions
[samba4-gss.git] / source4 / rpc_server / drsuapi / dcesrv_drsuapi.c
blob377cae41dd4825afdee235f6eb73763c8ffc11e4
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the drsuapi pipe
6 Copyright (C) Stefan Metzmacher 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_drsuapi.h"
25 #include "rpc_server/dcerpc_server.h"
26 #include "rpc_server/common/common.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "dsdb/common/util.h"
29 #include "libcli/security/security.h"
30 #include "libcli/security/session.h"
31 #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
32 #include "auth/auth.h"
33 #include "param/param.h"
34 #include "lib/messaging/irpc.h"
36 #undef strcasecmp
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_DRS_REPL
40 #define DRSUAPI_UNSUPPORTED(fname) do { \
41 DBG_WARNING(__location__ ": Unsupported DRS call %s\n", #fname); \
42 if (DEBUGLVL(DBGLVL_NOTICE)) NDR_PRINT_IN_DEBUG(fname, r); \
43 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); \
44 } while (0)
46 #define DCESRV_INTERFACE_DRSUAPI_BIND(context, iface) \
47 dcesrv_interface_drsuapi_bind(context, iface)
48 static NTSTATUS dcesrv_interface_drsuapi_bind(struct dcesrv_connection_context *context,
49 const struct dcesrv_interface *iface)
51 return dcesrv_interface_bind_require_privacy(context, iface);
54 /*
55 drsuapi_DsBind
57 static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
58 struct drsuapi_DsBind *r)
60 struct drsuapi_bind_state *b_state;
61 struct dcesrv_handle *handle;
62 struct drsuapi_DsBindInfoCtr *bind_info;
63 struct drsuapi_DsBindInfoCtr *local_info;
64 struct GUID site_guid, config_guid;
65 struct ldb_result *site_res, *config_res;
66 struct ldb_dn *server_site_dn, *config_dn;
67 static const char *site_attrs[] = { "objectGUID", NULL };
68 static const char *config_attrs[] = { "objectGUID", NULL };
69 struct ldb_result *ntds_res;
70 struct ldb_dn *ntds_dn;
71 static const char *ntds_attrs[] = { "ms-DS-ReplicationEpoch", NULL };
72 uint32_t pid;
73 uint32_t repl_epoch;
74 uint32_t supported_extensions;
75 uint32_t req_length;
76 int ret;
77 WERROR werr;
79 r->out.bind_info = NULL;
80 ZERO_STRUCTP(r->out.bind_handle);
82 b_state = talloc_zero(mem_ctx, struct drsuapi_bind_state);
83 W_ERROR_HAVE_NO_MEMORY(b_state);
85 /* if this is a DC connecting, give them system level access */
86 werr = drs_security_level_check(dce_call, NULL, SECURITY_DOMAIN_CONTROLLER, NULL);
87 if (W_ERROR_IS_OK(werr)) {
88 DBG_NOTICE("doing DsBind with system_session\n");
89 b_state->sam_ctx_system = dcesrv_samdb_connect_as_system(b_state, dce_call);
90 if (b_state->sam_ctx_system == NULL) {
91 return WERR_DS_UNAVAILABLE;
93 b_state->sam_ctx = b_state->sam_ctx_system;
94 } else {
95 b_state->sam_ctx = dcesrv_samdb_connect_as_user(b_state, dce_call);
96 if (b_state->sam_ctx == NULL) {
97 return WERR_DS_UNAVAILABLE;
101 * an RODC also needs system samdb access for secret
102 * attribute replication
104 werr = drs_security_level_check(dce_call, NULL, SECURITY_RO_DOMAIN_CONTROLLER,
105 samdb_domain_sid(b_state->sam_ctx));
106 if (W_ERROR_IS_OK(werr)) {
107 DBG_NOTICE("doing DsBind as RODC\n");
108 b_state->sam_ctx_system =
109 dcesrv_samdb_connect_as_system(b_state, dce_call);
110 if (b_state->sam_ctx_system == NULL) {
111 return WERR_DS_UNAVAILABLE;
117 * find out the guid of our own site
119 server_site_dn = samdb_server_site_dn(b_state->sam_ctx, mem_ctx);
120 W_ERROR_HAVE_NO_MEMORY(server_site_dn);
122 ret = ldb_search(b_state->sam_ctx, mem_ctx, &site_res,
123 server_site_dn, LDB_SCOPE_BASE, site_attrs,
124 "(objectClass=*)");
125 if (ret != LDB_SUCCESS) {
126 return WERR_DS_DRA_INTERNAL_ERROR;
128 if (site_res->count != 1) {
129 return WERR_DS_DRA_INTERNAL_ERROR;
131 site_guid = samdb_result_guid(site_res->msgs[0], "objectGUID");
134 * lookup the local servers Replication Epoch
136 ntds_dn = samdb_ntds_settings_dn(b_state->sam_ctx, mem_ctx);
137 W_ERROR_HAVE_NO_MEMORY(ntds_dn);
139 ret = ldb_search(b_state->sam_ctx, mem_ctx, &ntds_res,
140 ntds_dn, LDB_SCOPE_BASE, ntds_attrs,
141 "(objectClass=*)");
142 if (ret != LDB_SUCCESS) {
143 return WERR_DS_DRA_INTERNAL_ERROR;
145 if (ntds_res->count != 1) {
146 return WERR_DS_DRA_INTERNAL_ERROR;
148 repl_epoch = ldb_msg_find_attr_as_uint(ntds_res->msgs[0],
149 "ms-DS-ReplicationEpoch", 0);
152 * The "process identifier" of the client.
153 * According to the WSPP docs, section 5.35, this is
154 * for informational and debugging purposes only.
155 * The assignment is implementation specific.
157 pid = 0;
160 * store the clients bind_guid
162 if (r->in.bind_guid) {
163 b_state->remote_bind_guid = *r->in.bind_guid;
167 * store the clients bind_info
169 if (r->in.bind_info) {
170 b_state->remote_info = r->in.bind_info;
174 * fill in our local bind info
176 local_info = talloc_zero(mem_ctx, struct drsuapi_DsBindInfoCtr);
177 W_ERROR_HAVE_NO_MEMORY(local_info);
180 * Fill in supported extensions
182 supported_extensions = 0;
183 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
184 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
185 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
186 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
187 #if 0 /* we don't support MSZIP compression (only decompression) */
188 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
189 #endif
190 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
191 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
192 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
193 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
194 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
195 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
196 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
197 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
198 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
199 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
200 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
201 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
202 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
203 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
204 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5;
205 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
206 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
207 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
208 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
209 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
210 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
211 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
212 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
213 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
214 #if 0 /* we don't support XPRESS compression yet */
215 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
216 #endif
217 supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10;
220 * There is a chance for r->in.bind_info == NULL
221 * Currently we don't care, since it seems to be used nowhere else.
222 * But we need a request length. So use 28 as default.
224 req_length = 28;
225 if (r->in.bind_info) {
226 req_length = r->in.bind_info->length;
230 * fill 28 or 48 info, depends on request
232 if (req_length < 48) {
233 local_info->length = 28;
234 local_info->info.info28.supported_extensions = supported_extensions;
235 local_info->info.info28.site_guid = site_guid;
236 local_info->info.info28.pid = pid;
237 local_info->info.info28.repl_epoch = repl_epoch;
238 } else {
239 local_info->length = 48;
240 local_info->info.info48.supported_extensions = supported_extensions;
241 local_info->info.info48.site_guid = site_guid;
242 local_info->info.info48.pid = pid;
243 local_info->info.info48.repl_epoch = repl_epoch;
245 local_info->info.info48.supported_extensions_ext = 0;
246 local_info->info.info48.supported_extensions_ext |= DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2;
249 * find out the guid of our own site
251 config_dn = ldb_get_config_basedn(b_state->sam_ctx);
252 W_ERROR_HAVE_NO_MEMORY(config_dn);
254 ret = ldb_search(b_state->sam_ctx, mem_ctx, &config_res,
255 config_dn, LDB_SCOPE_BASE, config_attrs,
256 "(objectClass=*)");
257 if (ret != LDB_SUCCESS) {
258 return WERR_DS_DRA_INTERNAL_ERROR;
260 if (config_res->count != 1) {
261 return WERR_DS_DRA_INTERNAL_ERROR;
263 config_guid = samdb_result_guid(config_res->msgs[0], "objectGUID");
264 local_info->info.info48.config_dn_guid = config_guid;
268 * set local_info
270 b_state->local_info = local_info;
273 * set bind_info
275 bind_info = local_info;
278 * allocate a bind handle
280 handle = dcesrv_handle_create(dce_call, DRSUAPI_BIND_HANDLE);
281 W_ERROR_HAVE_NO_MEMORY(handle);
282 handle->data = talloc_steal(handle, b_state);
285 * prepare reply
287 r->out.bind_info = bind_info;
288 *r->out.bind_handle = handle->wire_handle;
290 return WERR_OK;
295 drsuapi_DsUnbind
297 static WERROR dcesrv_drsuapi_DsUnbind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
298 struct drsuapi_DsUnbind *r)
300 struct dcesrv_handle *h;
302 *r->out.bind_handle = *r->in.bind_handle;
304 DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
306 talloc_free(h);
308 ZERO_STRUCTP(r->out.bind_handle);
310 return WERR_OK;
315 drsuapi_DsReplicaSync
317 static WERROR dcesrv_drsuapi_DsReplicaSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
318 struct drsuapi_DsReplicaSync *r)
320 WERROR status;
321 uint32_t timeout;
323 status = drs_security_level_check(dce_call, "DsReplicaSync", SECURITY_DOMAIN_CONTROLLER, NULL);
324 if (!W_ERROR_IS_OK(status)) {
325 return status;
328 if (r->in.level != 1) {
329 DBG_ERR("DsReplicaSync called with unsupported level %d\n", r->in.level);
330 return WERR_DS_DRA_INVALID_PARAMETER;
333 if (r->in.req->req1.options & DRSUAPI_DRS_ASYNC_OP) {
334 timeout = IRPC_CALL_TIMEOUT;
335 } else {
337 * use Infinite time for timeout in case
338 * the caller made a sync call
340 timeout = IRPC_CALL_TIMEOUT_INF;
343 dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
344 r, NDR_DRSUAPI_DSREPLICASYNC,
345 &ndr_table_drsuapi,
346 "dreplsrv", "DsReplicaSync",
347 timeout);
349 return WERR_OK;
354 drsuapi_DsReplicaAdd
356 static WERROR dcesrv_drsuapi_DsReplicaAdd(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
357 struct drsuapi_DsReplicaAdd *r)
359 WERROR status;
361 status = drs_security_level_check(dce_call, "DsReplicaAdd", SECURITY_DOMAIN_CONTROLLER, NULL);
362 if (!W_ERROR_IS_OK(status)) {
363 return status;
366 dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
367 r, NDR_DRSUAPI_DSREPLICAADD,
368 &ndr_table_drsuapi,
369 "dreplsrv", "DsReplicaAdd",
370 IRPC_CALL_TIMEOUT);
372 return WERR_OK;
377 drsuapi_DsReplicaDel
379 static WERROR dcesrv_drsuapi_DsReplicaDel(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
380 struct drsuapi_DsReplicaDel *r)
382 WERROR status;
384 status = drs_security_level_check(dce_call, "DsReplicaDel", SECURITY_DOMAIN_CONTROLLER, NULL);
385 if (!W_ERROR_IS_OK(status)) {
386 return status;
389 dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
390 r, NDR_DRSUAPI_DSREPLICADEL,
391 &ndr_table_drsuapi,
392 "dreplsrv", "DsReplicaDel",
393 IRPC_CALL_TIMEOUT);
395 return WERR_OK;
400 drsuapi_DsReplicaModify
402 static WERROR dcesrv_drsuapi_DsReplicaMod(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
403 struct drsuapi_DsReplicaMod *r)
405 WERROR status;
407 status = drs_security_level_check(dce_call, "DsReplicaMod", SECURITY_DOMAIN_CONTROLLER, NULL);
408 if (!W_ERROR_IS_OK(status)) {
409 return status;
412 dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx,
413 r, NDR_DRSUAPI_DSREPLICAMOD,
414 &ndr_table_drsuapi,
415 "dreplsrv", "DsReplicaMod",
416 IRPC_CALL_TIMEOUT);
418 return WERR_OK;
423 DRSUAPI_VERIFY_NAMES
425 static WERROR dcesrv_DRSUAPI_VERIFY_NAMES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
426 struct DRSUAPI_VERIFY_NAMES *r)
428 DRSUAPI_UNSUPPORTED(DRSUAPI_VERIFY_NAMES);
433 drsuapi_DsGetMemberships
435 static WERROR dcesrv_drsuapi_DsGetMemberships(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
436 struct drsuapi_DsGetMemberships *r)
438 DRSUAPI_UNSUPPORTED(drsuapi_DsGetMemberships);
443 DRSUAPI_INTER_DOMAIN_MOVE
445 static WERROR dcesrv_DRSUAPI_INTER_DOMAIN_MOVE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
446 struct DRSUAPI_INTER_DOMAIN_MOVE *r)
448 DRSUAPI_UNSUPPORTED(DRSUAPI_INTER_DOMAIN_MOVE);
453 drsuapi_DsGetNT4ChangeLog
455 static WERROR dcesrv_drsuapi_DsGetNT4ChangeLog(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
456 struct drsuapi_DsGetNT4ChangeLog *r)
458 DRSUAPI_UNSUPPORTED(drsuapi_DsGetNT4ChangeLog);
462 drsuapi_DsCrackNames
464 static WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
465 struct drsuapi_DsCrackNames *r)
467 struct drsuapi_bind_state *b_state;
468 struct dcesrv_handle *h;
470 *r->out.level_out = r->in.level;
472 DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
473 b_state = h->data;
475 r->out.ctr = talloc_zero(mem_ctx, union drsuapi_DsNameCtr);
476 W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
478 switch (r->in.level) {
479 case 1: {
480 switch(r->in.req->req1.format_offered){
481 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX:
482 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN:
483 case DRSUAPI_DS_NAME_FORMAT_STRING_SID_NAME:
484 case DRSUAPI_DS_NAME_FORMAT_ALT_SECURITY_IDENTITIES_NAME:
485 case DRSUAPI_DS_NAME_FORMAT_MAP_SCHEMA_GUID:
486 case DRSUAPI_DS_NAME_FORMAT_LIST_NCS:
487 case DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS:
488 case DRSUAPI_DS_NAME_FORMAT_LIST_GLOBAL_CATALOG_SERVERS:
489 case DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_WITH_DCS_IN_SITE:
490 case DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_FOR_DOMAIN_IN_SITE:
491 case DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS_IN_SITE:
492 case DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_IN_SITE:
493 case DRSUAPI_DS_NAME_FORMAT_LIST_SITES:
494 case DRSUAPI_DS_NAME_FORMAT_UPN_AND_ALTSECID:
495 case DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON:
496 DBG_ERR("DsCrackNames: Unsupported operation requested: %X\n",
497 r->in.req->req1.format_offered);
498 return WERR_OK;
499 case DRSUAPI_DS_NAME_FORMAT_LIST_INFO_FOR_SERVER:
500 return dcesrv_drsuapi_ListInfoServer(b_state->sam_ctx, mem_ctx, &r->in.req->req1, &r->out.ctr->ctr1);
501 case DRSUAPI_DS_NAME_FORMAT_LIST_ROLES:
502 return dcesrv_drsuapi_ListRoles(b_state->sam_ctx, mem_ctx,
503 &r->in.req->req1, &r->out.ctr->ctr1);
504 default:/* format_offered is in the enum drsuapi_DsNameFormat*/
505 return dcesrv_drsuapi_CrackNamesByNameFormat(b_state->sam_ctx, mem_ctx,
506 &r->in.req->req1, &r->out.ctr->ctr1);
510 return WERR_INVALID_LEVEL;
515 drsuapi_DsRemoveDSServer
517 static WERROR dcesrv_drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
518 struct drsuapi_DsRemoveDSServer *r)
520 struct drsuapi_bind_state *b_state;
521 struct dcesrv_handle *h;
522 struct ldb_dn *ntds_dn;
523 int ret;
524 bool ok;
525 WERROR status;
527 *r->out.level_out = 1;
529 status = drs_security_level_check(dce_call, "DsRemoveDSServer", SECURITY_DOMAIN_CONTROLLER, NULL);
530 if (!W_ERROR_IS_OK(status)) {
531 return status;
534 DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
535 b_state = h->data;
537 switch (r->in.level) {
538 case 1:
539 ntds_dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, r->in.req->req1.server_dn);
540 W_ERROR_HAVE_NO_MEMORY(ntds_dn);
542 ok = ldb_dn_validate(ntds_dn);
543 if (!ok) {
544 return WERR_FOOBAR;
547 /* TODO: it's likely that we need more checks here */
549 ok = ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings");
550 if (!ok) {
551 return WERR_FOOBAR;
554 if (r->in.req->req1.commit) {
555 ret = dsdb_delete(b_state->sam_ctx, ntds_dn, DSDB_TREE_DELETE);
556 if (ret != LDB_SUCCESS) {
557 return WERR_FOOBAR;
561 return WERR_OK;
562 default:
563 break;
566 return WERR_FOOBAR;
571 DRSUAPI_REMOVE_DS_DOMAIN
573 static WERROR dcesrv_DRSUAPI_REMOVE_DS_DOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
574 struct DRSUAPI_REMOVE_DS_DOMAIN *r)
576 DRSUAPI_UNSUPPORTED(DRSUAPI_REMOVE_DS_DOMAIN);
579 /* Obtain the site name from a server DN */
580 static const char *result_site_name(struct ldb_dn *server_dn)
582 /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
583 const struct ldb_val *val = ldb_dn_get_component_val(server_dn, 2);
584 const char *name = ldb_dn_get_component_name(server_dn, 2);
586 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
587 /* Ensure this matches the format. This gives us a
588 * bit more confidence that a 'cn' value will be a
589 * ascii string */
590 return NULL;
592 if (val) {
593 return (char *)val->data;
595 return NULL;
599 drsuapi_DsGetDomainControllerInfo
601 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_state *b_state,
602 TALLOC_CTX *mem_ctx,
603 struct drsuapi_DsGetDomainControllerInfo *r)
605 struct ldb_dn *sites_dn;
606 struct ldb_result *res;
608 const char *attrs_account_1[] = { "cn", "dnsHostName", NULL };
609 const char *attrs_account_2[] = { "cn", "dnsHostName", "objectGUID", NULL };
611 const char *attrs_none[] = { NULL };
613 const char *attrs_site[] = { "objectGUID", NULL };
615 const char *attrs_ntds[] = { "options", "objectGUID", NULL };
617 const char *attrs_1[] = { "serverReference", "cn", "dnsHostName", NULL };
618 const char *attrs_2[] = { "serverReference", "cn", "dnsHostName", "objectGUID", NULL };
619 const char **attrs;
621 struct drsuapi_DsGetDCInfoCtr1 *ctr1;
622 struct drsuapi_DsGetDCInfoCtr2 *ctr2;
623 struct drsuapi_DsGetDCInfoCtr3 *ctr3;
625 int ret;
626 unsigned int i;
628 *r->out.level_out = r->in.req->req1.level;
629 r->out.ctr = talloc_zero(mem_ctx, union drsuapi_DsGetDCInfoCtr);
630 W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
632 switch (*r->out.level_out) {
633 case -1:
634 /* this level is not like the others */
635 return WERR_INVALID_LEVEL;
636 case 1:
637 attrs = attrs_1;
638 break;
639 case 2:
640 case 3:
641 attrs = attrs_2;
642 break;
643 default:
644 return WERR_INVALID_LEVEL;
647 sites_dn = samdb_sites_dn(b_state->sam_ctx, mem_ctx);
648 if (!sites_dn) {
649 return WERR_DS_OBJ_NOT_FOUND;
652 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res, sites_dn, LDB_SCOPE_SUBTREE, attrs,
653 "(&(objectClass=server)(serverReference=*))");
655 if (ret) {
656 DBG_WARNING("searching for servers in sites DN %s failed: %s\n",
657 ldb_dn_get_linearized(sites_dn), ldb_errstring(b_state->sam_ctx));
658 return WERR_GEN_FAILURE;
661 switch (*r->out.level_out) {
662 case 1:
663 ctr1 = &r->out.ctr->ctr1;
664 ctr1->count = res->count;
665 ctr1->array = talloc_zero_array(mem_ctx,
666 struct drsuapi_DsGetDCInfo1,
667 res->count);
668 for (i=0; i < res->count; i++) {
669 struct ldb_dn *domain_dn;
670 struct ldb_result *res_domain;
671 struct ldb_result *res_account;
672 struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
674 struct ldb_dn *ref_dn
675 = ldb_msg_find_attr_as_dn(b_state->sam_ctx,
676 mem_ctx, res->msgs[i],
677 "serverReference");
679 if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
680 return WERR_NOT_ENOUGH_MEMORY;
683 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
684 LDB_SCOPE_BASE, attrs_account_1,
685 "(&(objectClass=computer)(userAccountControl:"LDB_OID_COMPARATOR_AND":=%u))",
686 UF_SERVER_TRUST_ACCOUNT);
687 if (ret == LDB_SUCCESS && res_account->count == 1) {
688 const char *errstr;
689 ctr1->array[i].dns_name
690 = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
691 ctr1->array[i].netbios_name
692 = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
693 ctr1->array[i].computer_dn
694 = ldb_dn_get_linearized(res_account->msgs[0]->dn);
696 /* Determine if this is the PDC */
697 ret = samdb_search_for_parent_domain(b_state->sam_ctx,
698 mem_ctx, res_account->msgs[0]->dn,
699 &domain_dn, &errstr);
701 if (ret == LDB_SUCCESS) {
702 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
703 LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
704 ldb_dn_get_linearized(ntds_dn));
705 if (ret) {
706 return WERR_GEN_FAILURE;
708 if (res_domain->count == 1) {
709 ctr1->array[i].is_pdc = true;
713 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
714 DBG_INFO("warning: searching for computer DN %s failed: %s\n",
715 ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx));
718 /* Look at server DN and extract site component */
719 ctr1->array[i].site_name = result_site_name(res->msgs[i]->dn);
720 ctr1->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
723 ctr1->array[i].is_enabled = true;
726 break;
727 case 2:
728 ctr2 = &r->out.ctr->ctr2;
729 ctr2->count = res->count;
730 ctr2->array = talloc_zero_array(mem_ctx,
731 struct drsuapi_DsGetDCInfo2,
732 res->count);
733 for (i=0; i < res->count; i++) {
734 struct ldb_dn *domain_dn;
735 struct ldb_result *res_domain;
736 struct ldb_result *res_account;
737 struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
738 struct ldb_result *res_ntds;
739 struct ldb_dn *site_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
740 struct ldb_result *res_site;
741 struct ldb_dn *ref_dn
742 = ldb_msg_find_attr_as_dn(b_state->sam_ctx,
743 mem_ctx, res->msgs[i],
744 "serverReference");
746 if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
747 return WERR_NOT_ENOUGH_MEMORY;
750 /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
751 if (!site_dn || !ldb_dn_remove_child_components(site_dn, 2)) {
752 return WERR_NOT_ENOUGH_MEMORY;
755 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_ntds, ntds_dn,
756 LDB_SCOPE_BASE, attrs_ntds, "objectClass=nTDSDSA");
757 if (ret == LDB_SUCCESS && res_ntds->count == 1) {
758 ctr2->array[i].is_gc
759 = (ldb_msg_find_attr_as_uint(res_ntds->msgs[0], "options", 0) & DS_NTDSDSA_OPT_IS_GC);
760 ctr2->array[i].ntds_guid
761 = samdb_result_guid(res_ntds->msgs[0], "objectGUID");
762 ctr2->array[i].ntds_dn = ldb_dn_get_linearized(res_ntds->msgs[0]->dn);
764 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
765 DBG_INFO("warning: searching for NTDS DN %s failed: %s\n",
766 ldb_dn_get_linearized(ntds_dn), ldb_errstring(b_state->sam_ctx));
769 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_site, site_dn,
770 LDB_SCOPE_BASE, attrs_site, "objectClass=site");
771 if (ret == LDB_SUCCESS && res_site->count == 1) {
772 ctr2->array[i].site_guid
773 = samdb_result_guid(res_site->msgs[0], "objectGUID");
774 ctr2->array[i].site_dn = ldb_dn_get_linearized(res_site->msgs[0]->dn);
776 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
777 DBG_INFO("warning: searching for site DN %s failed: %s\n",
778 ldb_dn_get_linearized(site_dn), ldb_errstring(b_state->sam_ctx));
781 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
782 LDB_SCOPE_BASE, attrs_account_2, "objectClass=computer");
783 if (ret == LDB_SUCCESS && res_account->count == 1) {
784 const char *errstr;
785 ctr2->array[i].dns_name
786 = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
787 ctr2->array[i].netbios_name
788 = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
789 ctr2->array[i].computer_dn = ldb_dn_get_linearized(res_account->msgs[0]->dn);
790 ctr2->array[i].computer_guid
791 = samdb_result_guid(res_account->msgs[0], "objectGUID");
793 /* Determine if this is the PDC */
794 ret = samdb_search_for_parent_domain(b_state->sam_ctx,
795 mem_ctx, res_account->msgs[0]->dn,
796 &domain_dn, &errstr);
798 if (ret == LDB_SUCCESS) {
799 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
800 LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
801 ldb_dn_get_linearized(ntds_dn));
802 if (ret == LDB_SUCCESS && res_domain->count == 1) {
803 ctr2->array[i].is_pdc = true;
805 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
806 DBG_INFO("warning: searching for domain DN %s failed: %s\n",
807 ldb_dn_get_linearized(domain_dn), ldb_errstring(b_state->sam_ctx));
811 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
812 DBG_INFO("warning: searching for computer account DN %s failed: %s\n",
813 ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx));
816 /* Look at server DN and extract site component */
817 ctr2->array[i].site_name = result_site_name(res->msgs[i]->dn);
818 ctr2->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
819 ctr2->array[i].server_guid
820 = samdb_result_guid(res->msgs[i], "objectGUID");
822 ctr2->array[i].is_enabled = true;
825 break;
826 case 3:
827 ctr3 = &r->out.ctr->ctr3;
828 ctr3->count = res->count;
829 ctr3->array = talloc_zero_array(mem_ctx,
830 struct drsuapi_DsGetDCInfo3,
831 res->count);
832 for (i=0; i<res->count; i++) {
833 struct ldb_dn *domain_dn;
834 struct ldb_result *res_domain;
835 struct ldb_result *res_account;
836 struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
837 struct ldb_result *res_ntds;
838 struct ldb_dn *site_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
839 struct ldb_result *res_site;
840 bool is_rodc;
841 struct ldb_dn *ref_dn
842 = ldb_msg_find_attr_as_dn(b_state->sam_ctx,
843 mem_ctx, res->msgs[i],
844 "serverReference");
846 if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
847 return WERR_NOT_ENOUGH_MEMORY;
850 /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
851 if (!site_dn || !ldb_dn_remove_child_components(site_dn, 2)) {
852 return WERR_NOT_ENOUGH_MEMORY;
855 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_ntds, ntds_dn,
856 LDB_SCOPE_BASE, attrs_ntds, "objectClass=nTDSDSA");
857 if (ret == LDB_SUCCESS && res_ntds->count == 1) {
858 ctr3->array[i].is_gc
859 = (ldb_msg_find_attr_as_uint(res_ntds->msgs[0], "options", 0) & DS_NTDSDSA_OPT_IS_GC);
860 ctr3->array[i].ntds_guid
861 = samdb_result_guid(res_ntds->msgs[0], "objectGUID");
862 ctr3->array[i].ntds_dn = ldb_dn_get_linearized(res_ntds->msgs[0]->dn);
864 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
865 DBG_INFO("warning: searching for NTDS DN %s failed: %s\n",
866 ldb_dn_get_linearized(ntds_dn), ldb_errstring(b_state->sam_ctx));
869 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_site, site_dn,
870 LDB_SCOPE_BASE, attrs_site, "objectClass=site");
871 if (ret == LDB_SUCCESS && res_site->count == 1) {
872 ctr3->array[i].site_guid
873 = samdb_result_guid(res_site->msgs[0], "objectGUID");
874 ctr3->array[i].site_dn = ldb_dn_get_linearized(res_site->msgs[0]->dn);
876 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
877 DBG_INFO("warning: searching for site DN %s failed: %s\n",
878 ldb_dn_get_linearized(site_dn), ldb_errstring(b_state->sam_ctx));
881 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
882 LDB_SCOPE_BASE, attrs_account_2, "objectClass=computer");
883 if (ret == LDB_SUCCESS && res_account->count == 1) {
884 const char *errstr;
885 ctr3->array[i].dns_name
886 = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
887 ctr3->array[i].netbios_name
888 = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
889 ctr3->array[i].computer_dn = ldb_dn_get_linearized(res_account->msgs[0]->dn);
890 ctr3->array[i].computer_guid
891 = samdb_result_guid(res_account->msgs[0], "objectGUID");
893 /* Determine if this is the PDC */
894 ret = samdb_search_for_parent_domain(b_state->sam_ctx,
895 mem_ctx, res_account->msgs[0]->dn,
896 &domain_dn, &errstr);
898 if (ret == LDB_SUCCESS) {
899 ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
900 LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
901 ldb_dn_get_linearized(ntds_dn));
902 if (ret == LDB_SUCCESS && res_domain->count == 1) {
903 ctr3->array[i].is_pdc = true;
905 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
906 DBG_INFO("warning: searching for domain DN %s failed: %s\n",
907 ldb_dn_get_linearized(domain_dn), ldb_errstring(b_state->sam_ctx));
911 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
912 DBG_INFO("warning: searching for computer account DN %s failed: %s\n",
913 ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx));
916 /* Look at server DN and extract site component */
917 ctr3->array[i].site_name = result_site_name(res->msgs[i]->dn);
918 ctr3->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
919 ctr3->array[i].server_guid
920 = samdb_result_guid(res->msgs[i], "objectGUID");
922 ctr3->array[i].is_enabled = true;
924 /* rodc? */
925 ret = samdb_is_rodc(b_state->sam_ctx, &ctr3->array[i].server_guid, &is_rodc);
926 if (ret == LDB_SUCCESS && is_rodc) {
927 ctr3->array[i].is_rodc = true;
930 break;
931 default:
932 return WERR_INVALID_LEVEL;
934 return WERR_OK;
938 drsuapi_DsGetDomainControllerInfo
940 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
941 struct drsuapi_DsGetDomainControllerInfo *r)
943 struct dcesrv_handle *h;
944 struct drsuapi_bind_state *b_state;
945 DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
946 b_state = h->data;
948 switch (r->in.level) {
949 case 1:
950 return dcesrv_drsuapi_DsGetDomainControllerInfo_1(b_state, mem_ctx, r);
953 return WERR_INVALID_LEVEL;
959 drsuapi_DsExecuteKCC
961 static WERROR dcesrv_drsuapi_DsExecuteKCC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
962 struct drsuapi_DsExecuteKCC *r)
964 WERROR status;
965 uint32_t timeout;
966 status = drs_security_level_check(dce_call, "DsExecuteKCC", SECURITY_DOMAIN_CONTROLLER, NULL);
968 if (!W_ERROR_IS_OK(status)) {
969 return status;
971 if (r->in.req->ctr1.taskID != 0) {
972 return WERR_INVALID_PARAMETER;
974 if (r->in.req->ctr1.flags & DRSUAPI_DS_EXECUTE_KCC_ASYNCHRONOUS_OPERATION) {
975 timeout = IRPC_CALL_TIMEOUT;
976 } else {
978 * use Infinite time for timeout in case
979 * the caller made a sync call
981 timeout = IRPC_CALL_TIMEOUT_INF;
984 dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSEXECUTEKCC,
985 &ndr_table_drsuapi, "kccsrv", "DsExecuteKCC",
986 timeout);
987 DBG_DEBUG("Forwarded the call to execute the KCC\n");
988 return WERR_OK;
993 drsuapi_DsReplicaGetInfo
995 static WERROR dcesrv_drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
996 struct drsuapi_DsReplicaGetInfo *r)
998 struct auth_session_info *session_info =
999 dcesrv_call_session_info(dce_call);
1000 enum security_user_level level;
1002 if (!lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL,
1003 "drs", "disable_sec_check", false)) {
1004 level = security_session_user_level(session_info, NULL);
1005 if (level < SECURITY_DOMAIN_CONTROLLER) {
1006 DBG_WARNING(__location__ ": Administrator access required for DsReplicaGetInfo\n");
1007 security_token_debug(DBGC_DRS_REPL, 2,
1008 session_info->security_token);
1009 return WERR_DS_DRA_ACCESS_DENIED;
1013 dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICAGETINFO,
1014 &ndr_table_drsuapi, "kccsrv", "DsReplicaGetInfo",
1015 IRPC_CALL_TIMEOUT);
1017 return WERR_OK;
1022 DRSUAPI_ADD_SID_HISTORY
1024 static WERROR dcesrv_DRSUAPI_ADD_SID_HISTORY(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1025 struct DRSUAPI_ADD_SID_HISTORY *r)
1027 DRSUAPI_UNSUPPORTED(DRSUAPI_ADD_SID_HISTORY);
1031 drsuapi_DsGetMemberships2
1033 static WERROR dcesrv_drsuapi_DsGetMemberships2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1034 struct drsuapi_DsGetMemberships2 *r)
1036 DRSUAPI_UNSUPPORTED(drsuapi_DsGetMemberships2);
1040 DRSUAPI_REPLICA_VERIFY_OBJECTS
1042 static WERROR dcesrv_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1043 struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
1045 DRSUAPI_UNSUPPORTED(DRSUAPI_REPLICA_VERIFY_OBJECTS);
1050 DRSUAPI_GET_OBJECT_EXISTENCE
1052 static WERROR dcesrv_DRSUAPI_GET_OBJECT_EXISTENCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1053 struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
1055 DRSUAPI_UNSUPPORTED(DRSUAPI_GET_OBJECT_EXISTENCE);
1060 drsuapi_QuerySitesByCost
1062 static WERROR dcesrv_drsuapi_QuerySitesByCost(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1063 struct drsuapi_QuerySitesByCost *r)
1065 DRSUAPI_UNSUPPORTED(drsuapi_QuerySitesByCost);
1069 /* include the generated boilerplate */
1070 #include "librpc/gen_ndr/ndr_drsuapi_s.c"