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