6a6bc8be7ec4d12be71d5b9c488ef39774b15d9b
[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   drsuapi_DsWriteAccountSpn 
383 */
384 static WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
385                        struct drsuapi_DsWriteAccountSpn *r)
386 {
387         struct drsuapi_bind_state *b_state;
388         struct dcesrv_handle *h;
389
390         *r->out.level_out = r->in.level;
391
392         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
393         b_state = h->data;
394
395         r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult);
396         W_ERROR_HAVE_NO_MEMORY(r->out.res);
397
398         switch (r->in.level) {
399                 case 1: {
400                         struct drsuapi_DsWriteAccountSpnRequest1 *req;
401                         struct ldb_message *msg;
402                         int count, i, ret;
403                         req = &r->in.req->req1;
404                         count = req->count;
405
406                         msg = ldb_msg_new(mem_ctx);
407                         if (msg == NULL) {
408                                 return WERR_NOMEM;
409                         }
410
411                         msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn);
412                         if ( ! ldb_dn_validate(msg->dn)) {
413                                 r->out.res->res1.status = WERR_OK;
414                                 return WERR_OK;
415                         }
416                         
417                         /* construct mods */
418                         for (i = 0; i < count; i++) {
419                                 samdb_msg_add_string(b_state->sam_ctx, 
420                                                      msg, msg, "servicePrincipalName",
421                                                      req->spn_names[i].str);
422                         }
423                         for (i=0;i<msg->num_elements;i++) {
424                                 switch (req->operation) {
425                                 case DRSUAPI_DS_SPN_OPERATION_ADD:
426                                         msg->elements[i].flags = LDB_FLAG_MOD_ADD;
427                                         break;
428                                 case DRSUAPI_DS_SPN_OPERATION_REPLACE:
429                                         msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
430                                         break;
431                                 case DRSUAPI_DS_SPN_OPERATION_DELETE:
432                                         msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
433                                         break;
434                                 }
435                         }
436    
437                         /* Apply to database */
438
439                         ret = ldb_modify(b_state->sam_ctx, msg);
440                         if (ret != 0) {
441                                 DEBUG(0,("Failed to modify SPNs on %s: %s\n",
442                                          ldb_dn_get_linearized(msg->dn), 
443                                          ldb_errstring(b_state->sam_ctx)));
444                                 r->out.res->res1.status = WERR_ACCESS_DENIED;
445                         } else {
446                                 r->out.res->res1.status = WERR_OK;
447                         }
448
449                         return WERR_OK;
450                 }
451         }
452         
453         return WERR_UNKNOWN_LEVEL;
454 }
455
456
457 /* 
458   drsuapi_DsRemoveDSServer
459 */
460 static WERROR dcesrv_drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
461                                        struct drsuapi_DsRemoveDSServer *r)
462 {
463         struct drsuapi_bind_state *b_state;
464         struct dcesrv_handle *h;
465         struct ldb_dn *ntds_dn;
466         int ret;
467         bool ok;
468         WERROR status;
469
470         ZERO_STRUCT(r->out.res);
471         *r->out.level_out = 1;
472
473         status = drs_security_level_check(dce_call, "DsRemoveDSServer");
474         if (!W_ERROR_IS_OK(status)) {
475                 return status;
476         }
477
478         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
479         b_state = h->data;
480
481         switch (r->in.level) {
482         case 1:
483                 ntds_dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, r->in.req->req1.server_dn);
484                 W_ERROR_HAVE_NO_MEMORY(ntds_dn);
485
486                 ok = ldb_dn_validate(ntds_dn);
487                 if (!ok) {
488                         return WERR_FOOBAR;
489                 }
490
491                 /* TODO: it's likely that we need more checks here */
492
493                 ok = ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings");
494                 if (!ok) {
495                         return WERR_FOOBAR;
496                 }
497
498                 if (r->in.req->req1.commit) {
499                         ret = ldb_delete(b_state->sam_ctx, ntds_dn);
500                         if (ret != LDB_SUCCESS) {
501                                 return WERR_FOOBAR;
502                         }
503                 }
504
505                 return WERR_OK;
506         default:
507                 break;
508         }
509
510         return WERR_FOOBAR;
511 }
512
513
514 /* 
515   DRSUAPI_REMOVE_DS_DOMAIN 
516 */
517 static WERROR dcesrv_DRSUAPI_REMOVE_DS_DOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
518                        struct DRSUAPI_REMOVE_DS_DOMAIN *r)
519 {
520         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
521 }
522
523 /* Obtain the site name from a server DN */
524 static const char *result_site_name(struct ldb_dn *site_dn)
525 {
526         /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
527         const struct ldb_val *val = ldb_dn_get_component_val(site_dn, 2);
528         const char *name = ldb_dn_get_component_name(site_dn, 2);
529
530         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
531                 /* Ensure this matches the format.  This gives us a
532                  * bit more confidence that a 'cn' value will be a
533                  * ascii string */
534                 return NULL;
535         }
536         if (val) {
537                 return (char *)val->data;
538         }
539         return NULL;
540 }
541
542 /* 
543   drsuapi_DsGetDomainControllerInfo 
544 */
545 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_state *b_state, 
546                                                 TALLOC_CTX *mem_ctx,
547                                                 struct drsuapi_DsGetDomainControllerInfo *r)
548 {
549         struct ldb_dn *sites_dn;
550         struct ldb_result *res;
551
552         const char *attrs_account_1[] = { "cn", "dnsHostName", NULL };
553         const char *attrs_account_2[] = { "cn", "dnsHostName", "objectGUID", NULL };
554
555         const char *attrs_none[] = { NULL };
556
557         const char *attrs_site[] = { "objectGUID", NULL };
558
559         const char *attrs_ntds[] = { "options", "objectGUID", NULL };
560
561         const char *attrs_1[] = { "serverReference", "cn", "dnsHostName", NULL };
562         const char *attrs_2[] = { "serverReference", "cn", "dnsHostName", "objectGUID", NULL };
563         const char **attrs;
564
565         struct drsuapi_DsGetDCInfoCtr1 *ctr1;
566         struct drsuapi_DsGetDCInfoCtr2 *ctr2;
567
568         int ret, i;
569
570         *r->out.level_out = r->in.req->req1.level;
571         r->out.ctr = talloc(mem_ctx, union drsuapi_DsGetDCInfoCtr);
572         W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
573
574         sites_dn = samdb_sites_dn(b_state->sam_ctx, mem_ctx);
575         if (!sites_dn) {
576                 return WERR_DS_OBJ_NOT_FOUND;
577         }
578
579         switch (*r->out.level_out) {
580         case -1:
581                 /* this level is not like the others */
582                 return WERR_UNKNOWN_LEVEL;
583         case 1:
584                 attrs = attrs_1;
585                 break;
586         case 2:
587                 attrs = attrs_2;
588                 break;
589         default:
590                 return WERR_UNKNOWN_LEVEL;
591         }
592
593         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res, sites_dn, LDB_SCOPE_SUBTREE, attrs,
594                                  "objectClass=server");
595         
596         if (ret) {
597                 DEBUG(1, ("searching for servers in sites DN %s failed: %s\n", 
598                           ldb_dn_get_linearized(sites_dn), ldb_errstring(b_state->sam_ctx)));
599                 return WERR_GENERAL_FAILURE;
600         }
601
602         switch (*r->out.level_out) {
603         case 1:
604                 ctr1 = &r->out.ctr->ctr1;
605                 ctr1->count = res->count;
606                 ctr1->array = talloc_zero_array(mem_ctx, 
607                                                 struct drsuapi_DsGetDCInfo1, 
608                                                 res->count);
609                 for (i=0; i < res->count; i++) {
610                         struct ldb_dn *domain_dn;
611                         struct ldb_result *res_domain;
612                         struct ldb_result *res_account;
613                         struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
614                         
615                         struct ldb_dn *ref_dn
616                                 = ldb_msg_find_attr_as_dn(b_state->sam_ctx, 
617                                                           mem_ctx, res->msgs[i], 
618                                                           "serverReference");
619
620                         if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
621                                 return WERR_NOMEM;
622                         }
623
624                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
625                                                  LDB_SCOPE_BASE, attrs_account_1, "objectClass=computer");
626                         if (ret == LDB_SUCCESS && res_account->count == 1) {
627                                 const char *errstr;
628                                 ctr1->array[i].dns_name
629                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
630                                 ctr1->array[i].netbios_name
631                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
632                                 ctr1->array[i].computer_dn
633                                         = ldb_dn_get_linearized(res_account->msgs[0]->dn);
634
635                                 /* Determine if this is the PDC */
636                                 ret = samdb_search_for_parent_domain(b_state->sam_ctx, 
637                                                                      mem_ctx, res_account->msgs[0]->dn,
638                                                                      &domain_dn, &errstr);
639                                 
640                                 if (ret == LDB_SUCCESS) {
641                                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
642                                                                  LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
643                                                                  ldb_dn_get_linearized(ntds_dn));
644                                         if (ret) {
645                                                 return WERR_GENERAL_FAILURE;
646                                         }
647                                         if (res_domain->count == 1) {
648                                                 ctr1->array[i].is_pdc = true;
649                                         }
650                                 }
651                         }
652                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
653                                 DEBUG(5, ("warning: searching for computer DN %s failed: %s\n", 
654                                           ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx)));
655                         }
656
657                         /* Look at server DN and extract site component */
658                         ctr1->array[i].site_name = result_site_name(res->msgs[i]->dn);
659                         ctr1->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
660
661
662                         ctr1->array[i].is_enabled = true;
663
664                 }
665                 break;
666         case 2:
667                 ctr2 = &r->out.ctr->ctr2;
668                 ctr2->count = res->count;
669                 ctr2->array = talloc_zero_array(mem_ctx, 
670                                                  struct drsuapi_DsGetDCInfo2, 
671                                                  res->count);
672                 for (i=0; i < res->count; i++) {
673                         struct ldb_dn *domain_dn;
674                         struct ldb_result *res_domain;
675                         struct ldb_result *res_account;
676                         struct ldb_dn *ntds_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
677                         struct ldb_result *res_ntds;
678                         struct ldb_dn *site_dn = ldb_dn_copy(mem_ctx, res->msgs[i]->dn);
679                         struct ldb_result *res_site;
680                         struct ldb_dn *ref_dn
681                                 = ldb_msg_find_attr_as_dn(b_state->sam_ctx, 
682                                                           mem_ctx, res->msgs[i], 
683                                                           "serverReference");
684
685                         if (!ntds_dn || !ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings")) {
686                                 return WERR_NOMEM;
687                         }
688
689                         /* Format is cn=<NETBIOS name>,cn=Servers,cn=<site>,cn=sites.... */
690                         if (!site_dn || !ldb_dn_remove_child_components(site_dn, 2)) {
691                                 return WERR_NOMEM;
692                         }
693
694                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_ntds, ntds_dn,
695                                                  LDB_SCOPE_BASE, attrs_ntds, "objectClass=nTDSDSA");
696                         if (ret == LDB_SUCCESS && res_ntds->count == 1) {
697                                 ctr2->array[i].is_gc
698                                         = (ldb_msg_find_attr_as_int(res_ntds->msgs[0], "options", 0) == 1);
699                                 ctr2->array[i].ntds_guid 
700                                         = samdb_result_guid(res_ntds->msgs[0], "objectGUID");
701                                 ctr2->array[i].ntds_dn = ldb_dn_get_linearized(res_ntds->msgs[0]->dn);
702                         }
703                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
704                                 DEBUG(5, ("warning: searching for NTDS DN %s failed: %s\n", 
705                                           ldb_dn_get_linearized(ntds_dn), ldb_errstring(b_state->sam_ctx)));
706                         }
707
708                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_site, site_dn,
709                                                  LDB_SCOPE_BASE, attrs_site, "objectClass=site");
710                         if (ret == LDB_SUCCESS && res_site->count == 1) {
711                                 ctr2->array[i].site_guid 
712                                         = samdb_result_guid(res_site->msgs[0], "objectGUID");
713                                 ctr2->array[i].site_dn = ldb_dn_get_linearized(res_site->msgs[0]->dn);
714                         }
715                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
716                                 DEBUG(5, ("warning: searching for site DN %s failed: %s\n", 
717                                           ldb_dn_get_linearized(site_dn), ldb_errstring(b_state->sam_ctx)));
718                         }
719
720                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
721                                                  LDB_SCOPE_BASE, attrs_account_2, "objectClass=computer");
722                         if (ret == LDB_SUCCESS && res_account->count == 1) {
723                                 const char *errstr;
724                                 ctr2->array[i].dns_name
725                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
726                                 ctr2->array[i].netbios_name
727                                         = ldb_msg_find_attr_as_string(res_account->msgs[0], "cn", NULL);
728                                 ctr2->array[i].computer_dn = ldb_dn_get_linearized(res_account->msgs[0]->dn);
729                                 ctr2->array[i].computer_guid 
730                                         = samdb_result_guid(res_account->msgs[0], "objectGUID");
731
732                                 /* Determine if this is the PDC */
733                                 ret = samdb_search_for_parent_domain(b_state->sam_ctx, 
734                                                                      mem_ctx, res_account->msgs[0]->dn,
735                                                                      &domain_dn, &errstr);
736                                 
737                                 if (ret == LDB_SUCCESS) {
738                                         ret = ldb_search(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
739                                                                  LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
740                                                                  ldb_dn_get_linearized(ntds_dn));
741                                         if (ret == LDB_SUCCESS && res_domain->count == 1) {
742                                                 ctr2->array[i].is_pdc = true;
743                                         }
744                                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
745                                                 DEBUG(5, ("warning: searching for domain DN %s failed: %s\n", 
746                                                           ldb_dn_get_linearized(domain_dn), ldb_errstring(b_state->sam_ctx)));
747                                         }
748                                 }
749                         }
750                         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
751                                 DEBUG(5, ("warning: searching for computer account DN %s failed: %s\n", 
752                                           ldb_dn_get_linearized(ref_dn), ldb_errstring(b_state->sam_ctx)));
753                         }
754
755                         /* Look at server DN and extract site component */
756                         ctr2->array[i].site_name = result_site_name(res->msgs[i]->dn);
757                         ctr2->array[i].server_dn = ldb_dn_get_linearized(res->msgs[i]->dn);
758                         ctr2->array[i].server_guid 
759                                 = samdb_result_guid(res->msgs[i], "objectGUID");
760
761                         ctr2->array[i].is_enabled = true;
762
763                 }
764                 break;
765         }
766         return WERR_OK;
767 }
768
769 /* 
770   drsuapi_DsGetDomainControllerInfo 
771 */
772 static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
773                                                 struct drsuapi_DsGetDomainControllerInfo *r)
774 {
775         struct dcesrv_handle *h;
776         struct drsuapi_bind_state *b_state;     
777         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
778         b_state = h->data;
779
780         switch (r->in.level) {
781         case 1:
782                 return dcesrv_drsuapi_DsGetDomainControllerInfo_1(b_state, mem_ctx, r);
783         }
784
785         return WERR_UNKNOWN_LEVEL;
786 }
787
788
789
790 /* 
791   drsuapi_DsExecuteKCC 
792 */
793 static WERROR dcesrv_drsuapi_DsExecuteKCC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
794                                   struct drsuapi_DsExecuteKCC *r)
795 {
796         WERROR status;
797         status = drs_security_level_check(dce_call, "DsExecuteKCC");
798
799         if (!W_ERROR_IS_OK(status)) {
800                 return status;
801         }
802
803         dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSEXECUTEKCC,
804                                                                 &ndr_table_drsuapi, "kccsrv", "DsExecuteKCC");
805         return WERR_OK;
806 }
807
808
809 /* 
810   drsuapi_DsReplicaGetInfo 
811 */
812 static WERROR dcesrv_drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
813                        struct drsuapi_DsReplicaGetInfo *r)
814 {
815         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
816 }
817
818
819 /* 
820   DRSUAPI_ADD_SID_HISTORY 
821 */
822 static WERROR dcesrv_DRSUAPI_ADD_SID_HISTORY(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
823                        struct DRSUAPI_ADD_SID_HISTORY *r)
824 {
825         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
826 }
827
828 /* 
829   drsuapi_DsGetMemberships2 
830 */
831 static WERROR dcesrv_drsuapi_DsGetMemberships2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
832                        struct drsuapi_DsGetMemberships2 *r)
833 {
834         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
835 }
836
837 /* 
838   DRSUAPI_REPLICA_VERIFY_OBJECTS 
839 */
840 static WERROR dcesrv_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
841                        struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
842 {
843         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
844 }
845
846
847 /* 
848   DRSUAPI_GET_OBJECT_EXISTENCE 
849 */
850 static WERROR dcesrv_DRSUAPI_GET_OBJECT_EXISTENCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
851                        struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
852 {
853         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
854 }
855
856
857 /* 
858   drsuapi_QuerySitesByCost 
859 */
860 static WERROR dcesrv_drsuapi_QuerySitesByCost(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
861                        struct drsuapi_QuerySitesByCost *r)
862 {
863         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
864 }
865
866
867 /* include the generated boilerplate */
868 #include "librpc/gen_ndr/ndr_drsuapi_s.c"