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/>.
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"
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); \
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
);
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
};
74 uint32_t supported_extensions
;
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
;
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
,
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
,
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.
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
;
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
;
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.
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
;
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
,
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
;
270 b_state
->local_info
= local_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
);
287 r
->out
.bind_info
= bind_info
;
288 *r
->out
.bind_handle
= handle
->wire_handle
;
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
);
308 ZERO_STRUCTP(r
->out
.bind_handle
);
315 drsuapi_DsReplicaSync
317 static WERROR
dcesrv_drsuapi_DsReplicaSync(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
318 struct drsuapi_DsReplicaSync
*r
)
323 status
= drs_security_level_check(dce_call
, "DsReplicaSync", SECURITY_DOMAIN_CONTROLLER
, NULL
);
324 if (!W_ERROR_IS_OK(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
;
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
,
346 "dreplsrv", "DsReplicaSync",
356 static WERROR
dcesrv_drsuapi_DsReplicaAdd(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
357 struct drsuapi_DsReplicaAdd
*r
)
361 status
= drs_security_level_check(dce_call
, "DsReplicaAdd", SECURITY_DOMAIN_CONTROLLER
, NULL
);
362 if (!W_ERROR_IS_OK(status
)) {
366 dcesrv_irpc_forward_rpc_call(dce_call
, mem_ctx
,
367 r
, NDR_DRSUAPI_DSREPLICAADD
,
369 "dreplsrv", "DsReplicaAdd",
379 static WERROR
dcesrv_drsuapi_DsReplicaDel(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
380 struct drsuapi_DsReplicaDel
*r
)
384 status
= drs_security_level_check(dce_call
, "DsReplicaDel", SECURITY_DOMAIN_CONTROLLER
, NULL
);
385 if (!W_ERROR_IS_OK(status
)) {
389 dcesrv_irpc_forward_rpc_call(dce_call
, mem_ctx
,
390 r
, NDR_DRSUAPI_DSREPLICADEL
,
392 "dreplsrv", "DsReplicaDel",
400 drsuapi_DsReplicaModify
402 static WERROR
dcesrv_drsuapi_DsReplicaMod(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
403 struct drsuapi_DsReplicaMod
*r
)
407 status
= drs_security_level_check(dce_call
, "DsReplicaMod", SECURITY_DOMAIN_CONTROLLER
, NULL
);
408 if (!W_ERROR_IS_OK(status
)) {
412 dcesrv_irpc_forward_rpc_call(dce_call
, mem_ctx
,
413 r
, NDR_DRSUAPI_DSREPLICAMOD
,
415 "dreplsrv", "DsReplicaMod",
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
);
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
);
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
) {
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
);
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
;
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
)) {
534 DCESRV_PULL_HANDLE_WERR(h
, r
->in
.bind_handle
, DRSUAPI_BIND_HANDLE
);
537 switch (r
->in
.level
) {
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
);
547 /* TODO: it's likely that we need more checks here */
549 ok
= ldb_dn_add_child_fmt(ntds_dn
, "CN=NTDS Settings");
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
) {
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
593 return (char *)val
->data
;
599 drsuapi_DsGetDomainControllerInfo
601 static WERROR
dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_state
*b_state
,
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
};
621 struct drsuapi_DsGetDCInfoCtr1
*ctr1
;
622 struct drsuapi_DsGetDCInfoCtr2
*ctr2
;
623 struct drsuapi_DsGetDCInfoCtr3
*ctr3
;
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
) {
634 /* this level is not like the others */
635 return WERR_INVALID_LEVEL
;
644 return WERR_INVALID_LEVEL
;
647 sites_dn
= samdb_sites_dn(b_state
->sam_ctx
, mem_ctx
);
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=*))");
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
) {
663 ctr1
= &r
->out
.ctr
->ctr1
;
664 ctr1
->count
= res
->count
;
665 ctr1
->array
= talloc_zero_array(mem_ctx
,
666 struct drsuapi_DsGetDCInfo1
,
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
],
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) {
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
));
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;
728 ctr2
= &r
->out
.ctr
->ctr2
;
729 ctr2
->count
= res
->count
;
730 ctr2
->array
= talloc_zero_array(mem_ctx
,
731 struct drsuapi_DsGetDCInfo2
,
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
],
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) {
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) {
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;
827 ctr3
= &r
->out
.ctr
->ctr3
;
828 ctr3
->count
= res
->count
;
829 ctr3
->array
= talloc_zero_array(mem_ctx
,
830 struct drsuapi_DsGetDCInfo3
,
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
;
841 struct ldb_dn
*ref_dn
842 = ldb_msg_find_attr_as_dn(b_state
->sam_ctx
,
843 mem_ctx
, res
->msgs
[i
],
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) {
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) {
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;
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;
932 return WERR_INVALID_LEVEL
;
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
);
948 switch (r
->in
.level
) {
950 return dcesrv_drsuapi_DsGetDomainControllerInfo_1(b_state
, mem_ctx
, r
);
953 return WERR_INVALID_LEVEL
;
961 static WERROR
dcesrv_drsuapi_DsExecuteKCC(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
962 struct drsuapi_DsExecuteKCC
*r
)
966 status
= drs_security_level_check(dce_call
, "DsExecuteKCC", SECURITY_DOMAIN_CONTROLLER
, NULL
);
968 if (!W_ERROR_IS_OK(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
;
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",
987 DBG_DEBUG("Forwarded the call to execute the KCC\n");
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",
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"