s4-drs: open samdb with system credentials when authorised
[gd/samba-autobuild/.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(0,(__location__ ": doing DsBind with system_session\n"));
64                 auth_info = system_session(b_state, 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         if (0 /*domain.behavior_version == 2*/) {
163                 /* TODO: find out how this is really triggered! */
164                 b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
165         }
166         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
167         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
168         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
169         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
170         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
171         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
172         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
173         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
174         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
175         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
176         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
177         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
178         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
179         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
180         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
181         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
182         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
183         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
184         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
185 #if 0 /* we don't support XPRESS compression yet */
186         b_state->local_info28.supported_extensions      |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
187 #endif
188         b_state->local_info28.site_guid                 = site_guid;
189         b_state->local_info28.pid                       = pid;
190         b_state->local_info28.repl_epoch                = repl_epoch;
191
192         /*
193          * allocate the return bind_info
194          */
195         bind_info = talloc(mem_ctx, struct drsuapi_DsBindInfoCtr);
196         W_ERROR_HAVE_NO_MEMORY(bind_info);
197
198         bind_info->length       = 28;
199         bind_info->info.info28  = b_state->local_info28;
200
201         /*
202          * allocate a bind handle
203          */
204         handle = dcesrv_handle_new(dce_call->context, DRSUAPI_BIND_HANDLE);
205         W_ERROR_HAVE_NO_MEMORY(handle);
206         handle->data = talloc_steal(handle, b_state);
207
208         /*
209          * prepare reply
210          */
211         r->out.bind_info = bind_info;
212         *r->out.bind_handle = handle->wire_handle;
213
214         return WERR_OK;
215 }
216
217
218 /* 
219   drsuapi_DsUnbind 
220 */
221 static WERROR dcesrv_drsuapi_DsUnbind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
222                                struct drsuapi_DsUnbind *r)
223 {
224         struct dcesrv_handle *h;
225
226         *r->out.bind_handle = *r->in.bind_handle;
227
228         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
229
230         talloc_free(h);
231
232         ZERO_STRUCTP(r->out.bind_handle);
233
234         return WERR_OK;
235 }
236
237
238 /* 
239   drsuapi_DsReplicaSync 
240 */
241 static WERROR dcesrv_drsuapi_DsReplicaSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
242                                            struct drsuapi_DsReplicaSync *r)
243 {
244         WERROR status;
245
246         status = drs_security_level_check(dce_call, "DsReplicaSync");
247         if (!W_ERROR_IS_OK(status)) {
248                 return status;
249         }
250
251         dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICASYNC,
252                                      &ndr_table_drsuapi,
253                                      "dreplsrv", "DsReplicaSync");
254
255         return WERR_OK;
256 }
257
258
259 /* 
260   drsuapi_DsReplicaAdd 
261 */
262 static WERROR dcesrv_drsuapi_DsReplicaAdd(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
263                                           struct drsuapi_DsReplicaAdd *r)
264 {
265         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
266 }
267
268
269 /* 
270   drsuapi_DsReplicaDel 
271 */
272 static WERROR dcesrv_drsuapi_DsReplicaDel(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
273                                           struct drsuapi_DsReplicaDel *r)
274 {
275         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
276 }
277
278
279 /* 
280   drsuapi_DsReplicaModify 
281 */
282 static WERROR dcesrv_drsuapi_DsReplicaMod(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
283                                           struct drsuapi_DsReplicaMod *r)
284 {
285         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
286 }
287
288
289 /* 
290   DRSUAPI_VERIFY_NAMES 
291 */
292 static WERROR dcesrv_DRSUAPI_VERIFY_NAMES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
293                        struct DRSUAPI_VERIFY_NAMES *r)
294 {
295         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
296 }
297
298
299 /* 
300   drsuapi_DsGetMemberships 
301 */
302 static WERROR dcesrv_drsuapi_DsGetMemberships(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
303                        struct drsuapi_DsGetMemberships *r)
304 {
305         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
306 }
307
308
309 /* 
310   DRSUAPI_INTER_DOMAIN_MOVE 
311 */
312 static WERROR dcesrv_DRSUAPI_INTER_DOMAIN_MOVE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
313                        struct DRSUAPI_INTER_DOMAIN_MOVE *r)
314 {
315         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
316 }
317
318
319 /* 
320   drsuapi_DsGetNT4ChangeLog 
321 */
322 static WERROR dcesrv_drsuapi_DsGetNT4ChangeLog(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
323                        struct drsuapi_DsGetNT4ChangeLog *r)
324 {
325         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
326 }
327
328
329 /* 
330   drsuapi_DsCrackNames 
331 */
332 static WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
333                             struct drsuapi_DsCrackNames *r)
334 {
335         WERROR status;
336         struct drsuapi_bind_state *b_state;
337         struct dcesrv_handle *h;
338
339         *r->out.level_out = r->in.level;
340
341         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
342         b_state = h->data;
343
344         r->out.ctr = talloc_zero(mem_ctx, union drsuapi_DsNameCtr);
345         W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
346
347         switch (r->in.level) {
348                 case 1: {
349                         struct drsuapi_DsNameCtr1 *ctr1;
350                         struct drsuapi_DsNameInfo1 *names;
351                         int count;
352                         int i;
353
354                         ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
355                         W_ERROR_HAVE_NO_MEMORY(ctr1);
356
357                         count = r->in.req->req1.count;
358                         names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
359                         W_ERROR_HAVE_NO_MEMORY(names);
360
361                         for (i=0; i < count; i++) {
362                                 status = DsCrackNameOneName(b_state->sam_ctx, mem_ctx,
363                                                             r->in.req->req1.format_flags,
364                                                             r->in.req->req1.format_offered,
365                                                             r->in.req->req1.format_desired,
366                                                             r->in.req->req1.names[i].str,
367                                                             &names[i]);
368                                 if (!W_ERROR_IS_OK(status)) {
369                                         return status;
370                                 }
371                         }
372
373                         ctr1->count = count;
374                         ctr1->array = names;
375                         r->out.ctr->ctr1 = ctr1;
376
377                         return WERR_OK;
378                 }
379         }
380         
381         return WERR_UNKNOWN_LEVEL;
382 }
383
384 /* 
385   drsuapi_DsWriteAccountSpn 
386 */
387 static WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
388                        struct drsuapi_DsWriteAccountSpn *r)
389 {
390         struct drsuapi_bind_state *b_state;
391         struct dcesrv_handle *h;
392
393         *r->out.level_out = r->in.level;
394
395         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
396         b_state = h->data;
397
398         r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult);
399         W_ERROR_HAVE_NO_MEMORY(r->out.res);
400
401         switch (r->in.level) {
402                 case 1: {
403                         struct drsuapi_DsWriteAccountSpnRequest1 *req;
404                         struct ldb_message *msg;
405                         int count, i, ret;
406                         req = &r->in.req->req1;
407                         count = req->count;
408
409                         msg = ldb_msg_new(mem_ctx);
410                         if (msg == NULL) {
411                                 return WERR_NOMEM;
412                         }
413
414                         msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn);
415                         if ( ! ldb_dn_validate(msg->dn)) {
416                                 r->out.res->res1.status = WERR_OK;
417                                 return WERR_OK;
418                         }
419                         
420                         /* construct mods */
421                         for (i = 0; i < count; i++) {
422                                 samdb_msg_add_string(b_state->sam_ctx, 
423                                                      msg, msg, "servicePrincipalName",
424                                                      req->spn_names[i].str);
425                         }
426                         for (i=0;i<msg->num_elements;i++) {
427                                 switch (req->operation) {
428                                 case DRSUAPI_DS_SPN_OPERATION_ADD:
429                                         msg->elements[i].flags = LDB_FLAG_MOD_ADD;
430                                         break;
431                                 case DRSUAPI_DS_SPN_OPERATION_REPLACE:
432                                         msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
433                                         break;
434                                 case DRSUAPI_DS_SPN_OPERATION_DELETE:
435                                         msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
436                                         break;
437                                 }
438                         }
439    
440                         /* Apply to database */
441
442                         ret = ldb_modify(b_state->sam_ctx, msg);
443                         if (ret != 0) {
444                                 DEBUG(0,("Failed to modify SPNs on %s: %s\n",
445                                          ldb_dn_get_linearized(msg->dn), 
446                                          ldb_errstring(b_state->sam_ctx)));
447                                 r->out.res->res1.status = WERR_ACCESS_DENIED;
448                         } else {
449                                 r->out.res->res1.status = WERR_OK;
450                         }
451
452                         return WERR_OK;
453                 }
454         }
455         
456         return WERR_UNKNOWN_LEVEL;
457 }
458
459
460 /* 
461   drsuapi_DsRemoveDSServer
462 */
463 static WERROR dcesrv_drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
464                                        struct drsuapi_DsRemoveDSServer *r)
465 {
466         struct drsuapi_bind_state *b_state;
467         struct dcesrv_handle *h;
468         struct ldb_dn *ntds_dn;
469         int ret;
470         bool ok;
471         WERROR status;
472
473         ZERO_STRUCT(r->out.res);
474         *r->out.level_out = 1;
475
476         status = drs_security_level_check(dce_call, "DsRemoveDSServer");
477         if (!W_ERROR_IS_OK(status)) {
478                 return status;
479         }
480
481         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
482         b_state = h->data;
483
484         switch (r->in.level) {
485         case 1:
486                 ntds_dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, r->in.req->req1.server_dn);
487                 W_ERROR_HAVE_NO_MEMORY(ntds_dn);
488
489                 ok = ldb_dn_validate(ntds_dn);
490                 if (!ok) {
491                         return WERR_FOOBAR;
492                 }
493
494                 /* TODO: it's likely that we need more checks here */
495
496                 ok = ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings");
497                 if (!ok) {
498                         return WERR_FOOBAR;
499                 }
500
501                 if (r->in.req->req1.commit) {
502                         ret = ldb_delete(b_state->sam_ctx, ntds_dn);
503                         if (ret != LDB_SUCCESS) {
504                                 return WERR_FOOBAR;
505                         }
506                 }
507
508                 return WERR_OK;
509         default:
510                 break;
511         }
512
513         return WERR_FOOBAR;
514 }
515
516
517 /* 
518   DRSUAPI_REMOVE_DS_DOMAIN 
519 */
520 static WERROR dcesrv_DRSUAPI_REMOVE_DS_DOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
521                        struct DRSUAPI_REMOVE_DS_DOMAIN *r)
522 {
523         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
524 }
525
526 /* Obtain the site name from a server DN */
527 static const char *result_site_name(struct ldb_dn *site_dn)
528 {
529         /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
530         const struct ldb_val *val = ldb_dn_get_component_val(site_dn, 2);
531         const char *name = ldb_dn_get_component_name(site_dn, 2);
532
533         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
534                 /* Ensure this matches the format.  This gives us a
535                  * bit more confidence that a 'cn' value will be a
536                  * ascii string */
537                 return NULL;
538         }
539         if (val) {
540                 return (char *)val->data;
541         }
542         return NULL;
543 }
544
545 /* 
546   drsuapi_DsGetDomainControllerInfo 
547 */
548 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_state *b_state, 
549                                                 TALLOC_CTX *mem_ctx,
550                                                 struct drsuapi_DsGetDomainControllerInfo *r)
551 {
552         struct ldb_dn *sites_dn;
553         struct ldb_result *res;
554
555         const char *attrs_account_1[] = { "cn", "dnsHostName", NULL };
556         const char *attrs_account_2[] = { "cn", "dnsHostName", "objectGUID", NULL };
557
558         const char *attrs_none[] = { NULL };
559
560         const char *attrs_site[] = { "objectGUID", NULL };
561
562         const char *attrs_ntds[] = { "options", "objectGUID", NULL };
563
564         const char *attrs_1[] = { "serverReference", "cn", "dnsHostName", NULL };
565         const char *attrs_2[] = { "serverReference", "cn", "dnsHostName", "objectGUID", NULL };
566         const char **attrs;
567
568         struct drsuapi_DsGetDCInfoCtr1 *ctr1;
569         struct drsuapi_DsGetDCInfoCtr2 *ctr2;
570
571         int ret, i;
572
573         *r->out.level_out = r->in.req->req1.level;
574         r->out.ctr = talloc(mem_ctx, union drsuapi_DsGetDCInfoCtr);
575         W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
576
577         sites_dn = samdb_sites_dn(b_state->sam_ctx, mem_ctx);
578         if (!sites_dn) {
579                 return WERR_DS_OBJ_NOT_FOUND;
580         }
581
582         switch (*r->out.level_out) {
583         case -1:
584                 /* this level is not like the others */
585                 return WERR_UNKNOWN_LEVEL;
586         case 1:
587                 attrs = attrs_1;
588                 break;
589         case 2:
590                 attrs = attrs_2;
591                 break;
592         default:
593                 return WERR_UNKNOWN_LEVEL;
594         }
595
596         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res, sites_dn, LDB_SCOPE_SUBTREE, attrs,
597                                  "objectClass=server");
598         
599         if (ret) {
600                 DEBUG(1, ("searching for servers in sites DN %s failed: %s\n", 
601                           ldb_dn_get_linearized(sites_dn), ldb_errstring(b_state->sam_ctx)));
602                 return WERR_GENERAL_FAILURE;
603         }
604
605         switch (*r->out.level_out) {
606         case 1:
607                 ctr1 = &r->out.ctr->ctr1;
608                 ctr1->count = res->count;
609                 ctr1->array = talloc_zero_array(mem_ctx, 
610                                                 struct drsuapi_DsGetDCInfo1, 
611                                                 res->count);
612                 for (i=0; i < res->count; i++) {
613                         struct ldb_dn *domain_dn;
614                         struct ldb_result *res_domain;
615                         struct ldb_result *res_account;
616                         struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
617                         
618                         struct ldb_dn *ref_dn
619                                 = ldb_msg_find_attr_as_dn(b_state->sam_ctx, 
620                                                           mem_ctx, res->msgs[i], 
621                                                           "serverReference");
622
623                         if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
624                                 return WERR_NOMEM;
625                         }
626
627                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
628                                                  LDB_SCOPE_BASE, attrs_account_1, "objectClass=computer");
629                         if (ret == LDB_SUCCESS && res_account->count == 1) {
630                                 const char *errstr;
631                                 ctr1->array[i].dns_name
632                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
633                                 ctr1->array[i].netbios_name
634                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
635                                 ctr1->array[i].computer_dn
636                                         = ldb_dn_get_linearized(res_account->msgs[0]->dn);
637
638                                 /* Determine if this is the PDC */
639                                 ret = samdb_search_for_parent_domain(b_state->sam_ctx, 
640                                                                      mem_ctx, res_account->msgs[0]->dn,
641                                                                      &domain_dn, &errstr);
642                                 
643                                 if (ret == LDB_SUCCESS) {
644                                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
645                                                                  LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
646                                                                  ldb_dn_get_linearized(ntds_dn));
647                                         if (ret) {
648                                                 return WERR_GENERAL_FAILURE;
649                                         }
650                                         if (res_domain->count == 1) {
651                                                 ctr1->array[i].is_pdc = true;
652                                         }
653                                 }
654                         }
655                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
656                                 DEBUG(5, ("warning: searching for computer DN %s failed: %s\n", 
657                                           ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx)));
658                         }
659
660                         /* Look at server DN and extract site component */
661                         ctr1->array[i].site_name = result_site_name(res->msgs[i]->dn);
662                         ctr1->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
663
664
665                         ctr1->array[i].is_enabled = true;
666
667                 }
668                 break;
669         case 2:
670                 ctr2 = &r->out.ctr->ctr2;
671                 ctr2->count = res->count;
672                 ctr2->array = talloc_zero_array(mem_ctx, 
673                                                  struct drsuapi_DsGetDCInfo2, 
674                                                  res->count);
675                 for (i=0; i < res->count; i++) {
676                         struct ldb_dn *domain_dn;
677                         struct ldb_result *res_domain;
678                         struct ldb_result *res_account;
679                         struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
680                         struct ldb_result *res_ntds;
681                         struct ldb_dn *site_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
682                         struct ldb_result *res_site;
683                         struct ldb_dn *ref_dn
684                                 = ldb_msg_find_attr_as_dn(b_state->sam_ctx, 
685                                                           mem_ctx, res->msgs[i], 
686                                                           "serverReference");
687
688                         if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
689                                 return WERR_NOMEM;
690                         }
691
692                         /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
693                         if (!site_dn || !ldb_dn_remove_child_components(site_dn, 2)) {
694                                 return WERR_NOMEM;
695                         }
696
697                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_ntds, ntds_dn,
698                                                  LDB_SCOPE_BASE, attrs_ntds, "objectClass=nTDSDSA");
699                         if (ret == LDB_SUCCESS && res_ntds->count == 1) {
700                                 ctr2->array[i].is_gc
701                                         = (ldb_msg_find_attr_as_int(res_ntds->msgs[0], "options", 0) == 1);
702                                 ctr2->array[i].ntds_guid 
703                                         = samdb_result_guid(res_ntds->msgs[0], "objectGUID");
704                                 ctr2->array[i].ntds_dn = ldb_dn_get_linearized(res_ntds->msgs[0]->dn);
705                         }
706                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
707                                 DEBUG(5, ("warning: searching for NTDS DN %s failed: %s\n", 
708                                           ldb_dn_get_linearized(ntds_dn), ldb_errstring(b_state->sam_ctx)));
709                         }
710
711                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_site, site_dn,
712                                                  LDB_SCOPE_BASE, attrs_site, "objectClass=site");
713                         if (ret == LDB_SUCCESS && res_site->count == 1) {
714                                 ctr2->array[i].site_guid 
715                                         = samdb_result_guid(res_site->msgs[0], "objectGUID");
716                                 ctr2->array[i].site_dn = ldb_dn_get_linearized(res_site->msgs[0]->dn);
717                         }
718                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
719                                 DEBUG(5, ("warning: searching for site DN %s failed: %s\n", 
720                                           ldb_dn_get_linearized(site_dn), ldb_errstring(b_state->sam_ctx)));
721                         }
722
723                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
724                                                  LDB_SCOPE_BASE, attrs_account_2, "objectClass=computer");
725                         if (ret == LDB_SUCCESS && res_account->count == 1) {
726                                 const char *errstr;
727                                 ctr2->array[i].dns_name
728                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
729                                 ctr2->array[i].netbios_name
730                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
731                                 ctr2->array[i].computer_dn = ldb_dn_get_linearized(res_account->msgs[0]->dn);
732                                 ctr2->array[i].computer_guid 
733                                         = samdb_result_guid(res_account->msgs[0], "objectGUID");
734
735                                 /* Determine if this is the PDC */
736                                 ret = samdb_search_for_parent_domain(b_state->sam_ctx, 
737                                                                      mem_ctx, res_account->msgs[0]->dn,
738                                                                      &domain_dn, &errstr);
739                                 
740                                 if (ret == LDB_SUCCESS) {
741                                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
742                                                                  LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
743                                                                  ldb_dn_get_linearized(ntds_dn));
744                                         if (ret == LDB_SUCCESS && res_domain->count == 1) {
745                                                 ctr2->array[i].is_pdc = true;
746                                         }
747                                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
748                                                 DEBUG(5, ("warning: searching for domain DN %s failed: %s\n", 
749                                                           ldb_dn_get_linearized(domain_dn), ldb_errstring(b_state->sam_ctx)));
750                                         }
751                                 }
752                         }
753                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
754                                 DEBUG(5, ("warning: searching for computer account DN %s failed: %s\n", 
755                                           ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx)));
756                         }
757
758                         /* Look at server DN and extract site component */
759                         ctr2->array[i].site_name = result_site_name(res->msgs[i]->dn);
760                         ctr2->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
761                         ctr2->array[i].server_guid 
762                                 = samdb_result_guid(res->msgs[i], "objectGUID");
763
764                         ctr2->array[i].is_enabled = true;
765
766                 }
767                 break;
768         }
769         return WERR_OK;
770 }
771
772 /* 
773   drsuapi_DsGetDomainControllerInfo 
774 */
775 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
776                                                 struct drsuapi_DsGetDomainControllerInfo *r)
777 {
778         struct dcesrv_handle *h;
779         struct drsuapi_bind_state *b_state;     
780         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
781         b_state = h->data;
782
783         switch (r->in.level) {
784         case 1:
785                 return dcesrv_drsuapi_DsGetDomainControllerInfo_1(b_state, mem_ctx, r);
786         }
787
788         return WERR_UNKNOWN_LEVEL;
789 }
790
791
792
793 /* 
794   drsuapi_DsExecuteKCC 
795 */
796 static WERROR dcesrv_drsuapi_DsExecuteKCC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
797                                   struct drsuapi_DsExecuteKCC *r)
798 {
799         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
800 }
801
802
803 /* 
804   drsuapi_DsReplicaGetInfo 
805 */
806 static WERROR dcesrv_drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
807                        struct drsuapi_DsReplicaGetInfo *r)
808 {
809         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
810 }
811
812
813 /* 
814   DRSUAPI_ADD_SID_HISTORY 
815 */
816 static WERROR dcesrv_DRSUAPI_ADD_SID_HISTORY(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
817                        struct DRSUAPI_ADD_SID_HISTORY *r)
818 {
819         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
820 }
821
822 /* 
823   drsuapi_DsGetMemberships2 
824 */
825 static WERROR dcesrv_drsuapi_DsGetMemberships2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
826                        struct drsuapi_DsGetMemberships2 *r)
827 {
828         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
829 }
830
831 /* 
832   DRSUAPI_REPLICA_VERIFY_OBJECTS 
833 */
834 static WERROR dcesrv_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
835                        struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
836 {
837         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
838 }
839
840
841 /* 
842   DRSUAPI_GET_OBJECT_EXISTENCE 
843 */
844 static WERROR dcesrv_DRSUAPI_GET_OBJECT_EXISTENCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
845                        struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
846 {
847         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
848 }
849
850
851 /* 
852   drsuapi_QuerySitesByCost 
853 */
854 static WERROR dcesrv_drsuapi_QuerySitesByCost(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
855                        struct drsuapi_QuerySitesByCost *r)
856 {
857         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
858 }
859
860
861 /* include the generated boilerplate */
862 #include "librpc/gen_ndr/ndr_drsuapi_s.c"