9edb24edd521694f5a3a814a2eb2f8fed1ff6abb
[ira/wip.git] / source4 / rpc_server / drsuapi / dcesrv_drsuapi.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the drsuapi pipe
5
6    Copyright (C) Stefan Metzmacher 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8    
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.
13    
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.
18    
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/>.
21 */
22
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 "rpc_server/drsuapi/dcesrv_drsuapi.h"
29 #include "libcli/security/security.h"
30 #include "auth/auth.h"
31
32 /* 
33   drsuapi_DsBind 
34 */
35 static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
36                        struct drsuapi_DsBind *r)
37 {
38         struct drsuapi_bind_state *b_state;
39         struct dcesrv_handle *handle;
40         struct drsuapi_DsBindInfoCtr *bind_info;
41         struct GUID site_guid;
42         struct ldb_result *site_res;
43         struct ldb_dn *server_site_dn;
44         static const char *site_attrs[] = { "objectGUID", NULL };
45         struct ldb_result *ntds_res;
46         struct ldb_dn *ntds_dn;
47         static const char *ntds_attrs[] = { "ms-DS-ReplicationEpoch", NULL };
48         uint32_t pid;
49         uint32_t repl_epoch;
50         int ret;
51         struct auth_session_info *auth_info;
52         WERROR werr;
53
54         r->out.bind_info = NULL;
55         ZERO_STRUCTP(r->out.bind_handle);
56
57         b_state = talloc_zero(mem_ctx, struct drsuapi_bind_state);
58         W_ERROR_HAVE_NO_MEMORY(b_state);
59
60         /* if this is a DC connecting, give them system level access */
61         werr = drs_security_level_check(dce_call, NULL);
62         if (W_ERROR_IS_OK(werr)) {
63                 DEBUG(2,(__location__ ": doing DsBind with system_session\n"));
64                 auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
65         } else {
66                 auth_info = dce_call->conn->auth_state.session_info;
67         }
68
69         /*
70          * connect to the samdb
71          */
72         b_state->sam_ctx = samdb_connect(b_state, dce_call->event_ctx, 
73                                          dce_call->conn->dce_ctx->lp_ctx, auth_info); 
74         if (!b_state->sam_ctx) {
75                 return WERR_FOOBAR;
76         }
77
78         /*
79          * find out the guid of our own site
80          */
81         server_site_dn = samdb_server_site_dn(b_state->sam_ctx, mem_ctx);
82         W_ERROR_HAVE_NO_MEMORY(server_site_dn);
83
84         ret = ldb_search(b_state->sam_ctx, mem_ctx, &site_res,
85                                  server_site_dn, LDB_SCOPE_BASE, site_attrs,
86                                  "(objectClass=*)");
87         if (ret != LDB_SUCCESS) {
88                 return WERR_DS_DRA_INTERNAL_ERROR;
89         }
90         if (site_res->count != 1) {
91                 return WERR_DS_DRA_INTERNAL_ERROR;
92         }
93         site_guid = samdb_result_guid(site_res->msgs[0], "objectGUID");
94
95         /*
96          * lookup the local servers Replication Epoch
97          */
98         ntds_dn = samdb_ntds_settings_dn(b_state->sam_ctx);
99         W_ERROR_HAVE_NO_MEMORY(ntds_dn);
100
101         ret = ldb_search(b_state->sam_ctx, mem_ctx, &ntds_res,
102                                  ntds_dn, LDB_SCOPE_BASE, ntds_attrs,
103                                  "(objectClass=*)");
104         if (ret != LDB_SUCCESS) {
105                 return WERR_DS_DRA_INTERNAL_ERROR;
106         }
107         if (ntds_res->count != 1) {
108                 return WERR_DS_DRA_INTERNAL_ERROR;
109         }
110         repl_epoch = samdb_result_uint(ntds_res->msgs[0], "ms-DS-ReplicationEpoch", 0);
111
112         /*
113          * The "process identifier" of the client.
114          * According to the WSPP docs, sectin 5.35, this is
115          * for informational and debugging purposes only.
116          * The assignment is implementation specific.
117          */
118         pid = 0;
119
120         /*
121          * store the clients bind_guid
122          */
123         if (r->in.bind_guid) {
124                 b_state->remote_bind_guid = *r->in.bind_guid;
125         }
126
127         /*
128          * store the clients bind_info
129          */
130         if (r->in.bind_info) {
131                 switch (r->in.bind_info->length) {
132                 case 24: {
133                         struct drsuapi_DsBindInfo24 *info24;
134                         info24 = &r->in.bind_info->info.info24;
135                         b_state->remote_info28.supported_extensions     = info24->supported_extensions;
136                         b_state->remote_info28.site_guid                = info24->site_guid;
137                         b_state->remote_info28.pid                      = info24->pid;
138                         b_state->remote_info28.repl_epoch               = 0;
139                         break;
140                 }
141                 case 28:
142                         b_state->remote_info28 = r->in.bind_info->info.info28;
143                         break;
144                 }
145         }
146
147         /*
148          * fill in our local bind info 28
149          */
150         b_state->local_info28.supported_extensions      = 0;
151         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
152         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
153         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
154         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
155 #if 0 /* we don't support MSZIP compression (only decompression) */
156         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
157 #endif
158         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
159         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
160         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
161         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
162         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
163         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
164         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
165         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
166         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
167         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
168         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
169         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
170         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
171         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
172         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
173         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
174         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
175         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
176         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
177         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
178         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
179         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
180         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
181         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
182 #if 0 /* we don't support XPRESS compression yet */
183         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
184 #endif
185         b_state->local_info28.site_guid                 = site_guid;
186         b_state->local_info28.pid                       = pid;
187         b_state->local_info28.repl_epoch                = repl_epoch;
188
189         /*
190          * allocate the return bind_info
191          */
192         bind_info = talloc(mem_ctx, struct drsuapi_DsBindInfoCtr);
193         W_ERROR_HAVE_NO_MEMORY(bind_info);
194
195         bind_info->length       = 28;
196         bind_info->info.info28  = b_state->local_info28;
197
198         /*
199          * allocate a bind handle
200          */
201         handle = dcesrv_handle_new(dce_call->context, DRSUAPI_BIND_HANDLE);
202         W_ERROR_HAVE_NO_MEMORY(handle);
203         handle->data = talloc_steal(handle, b_state);
204
205         /*
206          * prepare reply
207          */
208         r->out.bind_info = bind_info;
209         *r->out.bind_handle = handle->wire_handle;
210
211         return WERR_OK;
212 }
213
214
215 /* 
216   drsuapi_DsUnbind 
217 */
218 static WERROR dcesrv_drsuapi_DsUnbind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
219                                struct drsuapi_DsUnbind *r)
220 {
221         struct dcesrv_handle *h;
222
223         *r->out.bind_handle = *r->in.bind_handle;
224
225         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
226
227         talloc_free(h);
228
229         ZERO_STRUCTP(r->out.bind_handle);
230
231         return WERR_OK;
232 }
233
234
235 /* 
236   drsuapi_DsReplicaSync 
237 */
238 static WERROR dcesrv_drsuapi_DsReplicaSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
239                                            struct drsuapi_DsReplicaSync *r)
240 {
241         WERROR status;
242
243         status = drs_security_level_check(dce_call, "DsReplicaSync");
244         if (!W_ERROR_IS_OK(status)) {
245                 return status;
246         }
247
248         dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICASYNC,
249                                      &ndr_table_drsuapi,
250                                      "dreplsrv", "DsReplicaSync");
251
252         return WERR_OK;
253 }
254
255
256 /* 
257   drsuapi_DsReplicaAdd 
258 */
259 static WERROR dcesrv_drsuapi_DsReplicaAdd(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
260                                           struct drsuapi_DsReplicaAdd *r)
261 {
262         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
263 }
264
265
266 /* 
267   drsuapi_DsReplicaDel 
268 */
269 static WERROR dcesrv_drsuapi_DsReplicaDel(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
270                                           struct drsuapi_DsReplicaDel *r)
271 {
272         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
273 }
274
275
276 /* 
277   drsuapi_DsReplicaModify 
278 */
279 static WERROR dcesrv_drsuapi_DsReplicaMod(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
280                                           struct drsuapi_DsReplicaMod *r)
281 {
282         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
283 }
284
285
286 /* 
287   DRSUAPI_VERIFY_NAMES 
288 */
289 static WERROR dcesrv_DRSUAPI_VERIFY_NAMES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
290                        struct DRSUAPI_VERIFY_NAMES *r)
291 {
292         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
293 }
294
295
296 /* 
297   drsuapi_DsGetMemberships 
298 */
299 static WERROR dcesrv_drsuapi_DsGetMemberships(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
300                        struct drsuapi_DsGetMemberships *r)
301 {
302         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
303 }
304
305
306 /* 
307   DRSUAPI_INTER_DOMAIN_MOVE 
308 */
309 static WERROR dcesrv_DRSUAPI_INTER_DOMAIN_MOVE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
310                        struct DRSUAPI_INTER_DOMAIN_MOVE *r)
311 {
312         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
313 }
314
315
316 /* 
317   drsuapi_DsGetNT4ChangeLog 
318 */
319 static WERROR dcesrv_drsuapi_DsGetNT4ChangeLog(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
320                        struct drsuapi_DsGetNT4ChangeLog *r)
321 {
322         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
323 }
324
325
326 /* 
327   drsuapi_DsCrackNames 
328 */
329 static WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
330                             struct drsuapi_DsCrackNames *r)
331 {
332         WERROR status;
333         struct drsuapi_bind_state *b_state;
334         struct dcesrv_handle *h;
335
336         *r->out.level_out = r->in.level;
337
338         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
339         b_state = h->data;
340
341         r->out.ctr = talloc_zero(mem_ctx, union drsuapi_DsNameCtr);
342         W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
343
344         switch (r->in.level) {
345                 case 1: {
346                         struct drsuapi_DsNameCtr1 *ctr1;
347                         struct drsuapi_DsNameInfo1 *names;
348                         int count;
349                         int i;
350
351                         ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
352                         W_ERROR_HAVE_NO_MEMORY(ctr1);
353
354                         count = r->in.req->req1.count;
355                         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
356                         W_ERROR_HAVE_NO_MEMORY(names);
357
358                         for (i=0; i < count; i++) {
359                                 status = DsCrackNameOneName(b_state->sam_ctx, mem_ctx,
360                                                             r->in.req->req1.format_flags,
361                                                             r->in.req->req1.format_offered,
362                                                             r->in.req->req1.format_desired,
363                                                             r->in.req->req1.names[i].str,
364                                                             &names[i]);
365                                 if (!W_ERROR_IS_OK(status)) {
366                                         return status;
367                                 }
368                         }
369
370                         ctr1->count = count;
371                         ctr1->array = names;
372                         r->out.ctr->ctr1 = ctr1;
373
374                         return WERR_OK;
375                 }
376         }
377         
378         return WERR_UNKNOWN_LEVEL;
379 }
380
381
382 /* 
383   drsuapi_DsRemoveDSServer
384 */
385 static WERROR dcesrv_drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
386                                        struct drsuapi_DsRemoveDSServer *r)
387 {
388         struct drsuapi_bind_state *b_state;
389         struct dcesrv_handle *h;
390         struct ldb_dn *ntds_dn;
391         int ret;
392         bool ok;
393         WERROR status;
394
395         ZERO_STRUCT(r->out.res);
396         *r->out.level_out = 1;
397
398         status = drs_security_level_check(dce_call, "DsRemoveDSServer");
399         if (!W_ERROR_IS_OK(status)) {
400                 return status;
401         }
402
403         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
404         b_state = h->data;
405
406         switch (r->in.level) {
407         case 1:
408                 ntds_dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, r->in.req->req1.server_dn);
409                 W_ERROR_HAVE_NO_MEMORY(ntds_dn);
410
411                 ok = ldb_dn_validate(ntds_dn);
412                 if (!ok) {
413                         return WERR_FOOBAR;
414                 }
415
416                 /* TODO: it's likely that we need more checks here */
417
418                 ok = ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings");
419                 if (!ok) {
420                         return WERR_FOOBAR;
421                 }
422
423                 if (r->in.req->req1.commit) {
424                         ret = ldb_delete(b_state->sam_ctx, ntds_dn);
425                         if (ret != LDB_SUCCESS) {
426                                 return WERR_FOOBAR;
427                         }
428                 }
429
430                 return WERR_OK;
431         default:
432                 break;
433         }
434
435         return WERR_FOOBAR;
436 }
437
438
439 /* 
440   DRSUAPI_REMOVE_DS_DOMAIN 
441 */
442 static WERROR dcesrv_DRSUAPI_REMOVE_DS_DOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
443                        struct DRSUAPI_REMOVE_DS_DOMAIN *r)
444 {
445         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
446 }
447
448 /* Obtain the site name from a server DN */
449 static const char *result_site_name(struct ldb_dn *site_dn)
450 {
451         /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
452         const struct ldb_val *val = ldb_dn_get_component_val(site_dn, 2);
453         const char *name = ldb_dn_get_component_name(site_dn, 2);
454
455         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
456                 /* Ensure this matches the format.  This gives us a
457                  * bit more confidence that a 'cn' value will be a
458                  * ascii string */
459                 return NULL;
460         }
461         if (val) {
462                 return (char *)val->data;
463         }
464         return NULL;
465 }
466
467 /* 
468   drsuapi_DsGetDomainControllerInfo 
469 */
470 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_state *b_state, 
471                                                 TALLOC_CTX *mem_ctx,
472                                                 struct drsuapi_DsGetDomainControllerInfo *r)
473 {
474         struct ldb_dn *sites_dn;
475         struct ldb_result *res;
476
477         const char *attrs_account_1[] = { "cn", "dnsHostName", NULL };
478         const char *attrs_account_2[] = { "cn", "dnsHostName", "objectGUID", NULL };
479
480         const char *attrs_none[] = { NULL };
481
482         const char *attrs_site[] = { "objectGUID", NULL };
483
484         const char *attrs_ntds[] = { "options", "objectGUID", NULL };
485
486         const char *attrs_1[] = { "serverReference", "cn", "dnsHostName", NULL };
487         const char *attrs_2[] = { "serverReference", "cn", "dnsHostName", "objectGUID", NULL };
488         const char **attrs;
489
490         struct drsuapi_DsGetDCInfoCtr1 *ctr1;
491         struct drsuapi_DsGetDCInfoCtr2 *ctr2;
492
493         int ret, i;
494
495         *r->out.level_out = r->in.req->req1.level;
496         r->out.ctr = talloc(mem_ctx, union drsuapi_DsGetDCInfoCtr);
497         W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
498
499         sites_dn = samdb_sites_dn(b_state->sam_ctx, mem_ctx);
500         if (!sites_dn) {
501                 return WERR_DS_OBJ_NOT_FOUND;
502         }
503
504         switch (*r->out.level_out) {
505         case -1:
506                 /* this level is not like the others */
507                 return WERR_UNKNOWN_LEVEL;
508         case 1:
509                 attrs = attrs_1;
510                 break;
511         case 2:
512                 attrs = attrs_2;
513                 break;
514         default:
515                 return WERR_UNKNOWN_LEVEL;
516         }
517
518         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res, sites_dn, LDB_SCOPE_SUBTREE, attrs,
519                                  "objectClass=server");
520         
521         if (ret) {
522                 DEBUG(1, ("searching for servers in sites DN %s failed: %s\n", 
523                           ldb_dn_get_linearized(sites_dn), ldb_errstring(b_state->sam_ctx)));
524                 return WERR_GENERAL_FAILURE;
525         }
526
527         switch (*r->out.level_out) {
528         case 1:
529                 ctr1 = &r->out.ctr->ctr1;
530                 ctr1->count = res->count;
531                 ctr1->array = talloc_zero_array(mem_ctx, 
532                                                 struct drsuapi_DsGetDCInfo1, 
533                                                 res->count);
534                 for (i=0; i < res->count; i++) {
535                         struct ldb_dn *domain_dn;
536                         struct ldb_result *res_domain;
537                         struct ldb_result *res_account;
538                         struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
539                         
540                         struct ldb_dn *ref_dn
541                                 = ldb_msg_find_attr_as_dn(b_state->sam_ctx, 
542                                                           mem_ctx, res->msgs[i], 
543                                                           "serverReference");
544
545                         if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
546                                 return WERR_NOMEM;
547                         }
548
549                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
550                                                  LDB_SCOPE_BASE, attrs_account_1, "objectClass=computer");
551                         if (ret == LDB_SUCCESS && res_account->count == 1) {
552                                 const char *errstr;
553                                 ctr1->array[i].dns_name
554                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
555                                 ctr1->array[i].netbios_name
556                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
557                                 ctr1->array[i].computer_dn
558                                         = ldb_dn_get_linearized(res_account->msgs[0]->dn);
559
560                                 /* Determine if this is the PDC */
561                                 ret = samdb_search_for_parent_domain(b_state->sam_ctx, 
562                                                                      mem_ctx, res_account->msgs[0]->dn,
563                                                                      &domain_dn, &errstr);
564                                 
565                                 if (ret == LDB_SUCCESS) {
566                                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
567                                                                  LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
568                                                                  ldb_dn_get_linearized(ntds_dn));
569                                         if (ret) {
570                                                 return WERR_GENERAL_FAILURE;
571                                         }
572                                         if (res_domain->count == 1) {
573                                                 ctr1->array[i].is_pdc = true;
574                                         }
575                                 }
576                         }
577                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
578                                 DEBUG(5, ("warning: searching for computer DN %s failed: %s\n", 
579                                           ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx)));
580                         }
581
582                         /* Look at server DN and extract site component */
583                         ctr1->array[i].site_name = result_site_name(res->msgs[i]->dn);
584                         ctr1->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
585
586
587                         ctr1->array[i].is_enabled = true;
588
589                 }
590                 break;
591         case 2:
592                 ctr2 = &r->out.ctr->ctr2;
593                 ctr2->count = res->count;
594                 ctr2->array = talloc_zero_array(mem_ctx, 
595                                                  struct drsuapi_DsGetDCInfo2, 
596                                                  res->count);
597                 for (i=0; i < res->count; i++) {
598                         struct ldb_dn *domain_dn;
599                         struct ldb_result *res_domain;
600                         struct ldb_result *res_account;
601                         struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
602                         struct ldb_result *res_ntds;
603                         struct ldb_dn *site_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
604                         struct ldb_result *res_site;
605                         struct ldb_dn *ref_dn
606                                 = ldb_msg_find_attr_as_dn(b_state->sam_ctx, 
607                                                           mem_ctx, res->msgs[i], 
608                                                           "serverReference");
609
610                         if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
611                                 return WERR_NOMEM;
612                         }
613
614                         /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
615                         if (!site_dn || !ldb_dn_remove_child_components(site_dn, 2)) {
616                                 return WERR_NOMEM;
617                         }
618
619                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_ntds, ntds_dn,
620                                                  LDB_SCOPE_BASE, attrs_ntds, "objectClass=nTDSDSA");
621                         if (ret == LDB_SUCCESS && res_ntds->count == 1) {
622                                 ctr2->array[i].is_gc
623                                         = (ldb_msg_find_attr_as_int(res_ntds->msgs[0], "options", 0) == 1);
624                                 ctr2->array[i].ntds_guid 
625                                         = samdb_result_guid(res_ntds->msgs[0], "objectGUID");
626                                 ctr2->array[i].ntds_dn = ldb_dn_get_linearized(res_ntds->msgs[0]->dn);
627                         }
628                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
629                                 DEBUG(5, ("warning: searching for NTDS DN %s failed: %s\n", 
630                                           ldb_dn_get_linearized(ntds_dn), ldb_errstring(b_state->sam_ctx)));
631                         }
632
633                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_site, site_dn,
634                                                  LDB_SCOPE_BASE, attrs_site, "objectClass=site");
635                         if (ret == LDB_SUCCESS && res_site->count == 1) {
636                                 ctr2->array[i].site_guid 
637                                         = samdb_result_guid(res_site->msgs[0], "objectGUID");
638                                 ctr2->array[i].site_dn = ldb_dn_get_linearized(res_site->msgs[0]->dn);
639                         }
640                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
641                                 DEBUG(5, ("warning: searching for site DN %s failed: %s\n", 
642                                           ldb_dn_get_linearized(site_dn), ldb_errstring(b_state->sam_ctx)));
643                         }
644
645                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
646                                                  LDB_SCOPE_BASE, attrs_account_2, "objectClass=computer");
647                         if (ret == LDB_SUCCESS && res_account->count == 1) {
648                                 const char *errstr;
649                                 ctr2->array[i].dns_name
650                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
651                                 ctr2->array[i].netbios_name
652                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
653                                 ctr2->array[i].computer_dn = ldb_dn_get_linearized(res_account->msgs[0]->dn);
654                                 ctr2->array[i].computer_guid 
655                                         = samdb_result_guid(res_account->msgs[0], "objectGUID");
656
657                                 /* Determine if this is the PDC */
658                                 ret = samdb_search_for_parent_domain(b_state->sam_ctx, 
659                                                                      mem_ctx, res_account->msgs[0]->dn,
660                                                                      &domain_dn, &errstr);
661                                 
662                                 if (ret == LDB_SUCCESS) {
663                                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
664                                                                  LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
665                                                                  ldb_dn_get_linearized(ntds_dn));
666                                         if (ret == LDB_SUCCESS && res_domain->count == 1) {
667                                                 ctr2->array[i].is_pdc = true;
668                                         }
669                                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
670                                                 DEBUG(5, ("warning: searching for domain DN %s failed: %s\n", 
671                                                           ldb_dn_get_linearized(domain_dn), ldb_errstring(b_state->sam_ctx)));
672                                         }
673                                 }
674                         }
675                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
676                                 DEBUG(5, ("warning: searching for computer account DN %s failed: %s\n", 
677                                           ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx)));
678                         }
679
680                         /* Look at server DN and extract site component */
681                         ctr2->array[i].site_name = result_site_name(res->msgs[i]->dn);
682                         ctr2->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
683                         ctr2->array[i].server_guid 
684                                 = samdb_result_guid(res->msgs[i], "objectGUID");
685
686                         ctr2->array[i].is_enabled = true;
687
688                 }
689                 break;
690         }
691         return WERR_OK;
692 }
693
694 /* 
695   drsuapi_DsGetDomainControllerInfo 
696 */
697 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
698                                                 struct drsuapi_DsGetDomainControllerInfo *r)
699 {
700         struct dcesrv_handle *h;
701         struct drsuapi_bind_state *b_state;     
702         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
703         b_state = h->data;
704
705         switch (r->in.level) {
706         case 1:
707                 return dcesrv_drsuapi_DsGetDomainControllerInfo_1(b_state, mem_ctx, r);
708         }
709
710         return WERR_UNKNOWN_LEVEL;
711 }
712
713
714
715 /* 
716   drsuapi_DsExecuteKCC 
717 */
718 static WERROR dcesrv_drsuapi_DsExecuteKCC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
719                                   struct drsuapi_DsExecuteKCC *r)
720 {
721         WERROR status;
722         status = drs_security_level_check(dce_call, "DsExecuteKCC");
723
724         if (!W_ERROR_IS_OK(status)) {
725                 return status;
726         }
727
728         dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSEXECUTEKCC,
729                                                                 &ndr_table_drsuapi, "kccsrv", "DsExecuteKCC");
730         return WERR_OK;
731 }
732
733
734 /* 
735   drsuapi_DsReplicaGetInfo 
736 */
737 static WERROR dcesrv_drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
738                        struct drsuapi_DsReplicaGetInfo *r)
739 {
740         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
741 }
742
743
744 /* 
745   DRSUAPI_ADD_SID_HISTORY 
746 */
747 static WERROR dcesrv_DRSUAPI_ADD_SID_HISTORY(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
748                        struct DRSUAPI_ADD_SID_HISTORY *r)
749 {
750         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
751 }
752
753 /* 
754   drsuapi_DsGetMemberships2 
755 */
756 static WERROR dcesrv_drsuapi_DsGetMemberships2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
757                        struct drsuapi_DsGetMemberships2 *r)
758 {
759         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
760 }
761
762 /* 
763   DRSUAPI_REPLICA_VERIFY_OBJECTS 
764 */
765 static WERROR dcesrv_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
766                        struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
767 {
768         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
769 }
770
771
772 /* 
773   DRSUAPI_GET_OBJECT_EXISTENCE 
774 */
775 static WERROR dcesrv_DRSUAPI_GET_OBJECT_EXISTENCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
776                        struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
777 {
778         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
779 }
780
781
782 /* 
783   drsuapi_QuerySitesByCost 
784 */
785 static WERROR dcesrv_drsuapi_QuerySitesByCost(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
786                        struct drsuapi_QuerySitesByCost *r)
787 {
788         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
789 }
790
791
792 /* include the generated boilerplate */
793 #include "librpc/gen_ndr/ndr_drsuapi_s.c"