samba_kcc: Enable the python samba_kcc
[kai/samba-autobuild/.git] / source4 / dsdb / kcc / kcc_service.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    KCC service
5    
6    Copyright (C) Andrew Tridgell 2009
7    based on repl service code
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
24 #include "includes.h"
25 #include "dsdb/samdb/samdb.h"
26 #include "auth/auth.h"
27 #include "smbd/service.h"
28 #include "lib/events/events.h"
29 #include "lib/messaging/irpc.h"
30 #include "dsdb/kcc/kcc_service.h"
31 #include <ldb_errors.h>
32 #include "../lib/util/dlinklist.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "librpc/gen_ndr/ndr_drsuapi.h"
35 #include "librpc/gen_ndr/ndr_drsblobs.h"
36 #include "param/param.h"
37 #include "libds/common/roles.h"
38
39 /*
40   establish system creds
41  */
42 static WERROR kccsrv_init_creds(struct kccsrv_service *service)
43 {
44         service->system_session_info = system_session(service->task->lp_ctx);
45         if (!service->system_session_info) {
46                 return WERR_NOMEM;
47         }
48
49         return WERR_OK;
50 }
51
52 /*
53   connect to the local SAM
54  */
55 static WERROR kccsrv_connect_samdb(struct kccsrv_service *service, struct loadparm_context *lp_ctx)
56 {
57         const struct GUID *ntds_guid;
58
59         service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx, service->system_session_info, 0);
60         if (!service->samdb) {
61                 return WERR_DS_UNAVAILABLE;
62         }
63
64         ntds_guid = samdb_ntds_objectGUID(service->samdb);
65         if (!ntds_guid) {
66                 return WERR_DS_UNAVAILABLE;
67         }
68
69         service->ntds_guid = *ntds_guid;
70
71         if (samdb_rodc(service->samdb, &service->am_rodc) != LDB_SUCCESS) {
72                 DEBUG(0,(__location__ ": Failed to determine RODC status\n"));
73                 return WERR_DS_UNAVAILABLE;
74         }
75
76         return WERR_OK;
77 }
78
79
80 /*
81   load our local partition list
82  */
83 static WERROR kccsrv_load_partitions(struct kccsrv_service *s)
84 {
85         struct ldb_dn *basedn;
86         struct ldb_result *r;
87         struct ldb_message_element *el;
88         static const char *attrs[] = { "namingContexts", "configurationNamingContext", NULL };
89         unsigned int i;
90         int ret;
91
92         basedn = ldb_dn_new(s, s->samdb, NULL);
93         W_ERROR_HAVE_NO_MEMORY(basedn);
94
95         ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
96                          "(objectClass=*)");
97         talloc_free(basedn);
98         if (ret != LDB_SUCCESS) {
99                 return WERR_FOOBAR;
100         } else if (r->count != 1) {
101                 talloc_free(r);
102                 return WERR_FOOBAR;
103         }
104
105         el = ldb_msg_find_element(r->msgs[0], "namingContexts");
106         if (!el) {
107                 return WERR_FOOBAR;
108         }
109
110         for (i=0; i < el->num_values; i++) {
111                 const char *v = (const char *)el->values[i].data;
112                 struct ldb_dn *pdn;
113                 struct kccsrv_partition *p;
114
115                 pdn = ldb_dn_new(s, s->samdb, v);
116                 if (!ldb_dn_validate(pdn)) {
117                         return WERR_FOOBAR;
118                 }
119
120                 p = talloc_zero(s, struct kccsrv_partition);
121                 W_ERROR_HAVE_NO_MEMORY(p);
122
123                 p->dn = talloc_steal(p, pdn);
124                 p->service = s;
125
126                 DLIST_ADD(s->partitions, p);
127
128                 DEBUG(2, ("kccsrv_partition[%s] loaded\n", v));
129         }
130
131         el = ldb_msg_find_element(r->msgs[0], "configurationNamingContext");
132         if (!el) {
133                 return WERR_FOOBAR;
134         }
135         s->config_dn = ldb_dn_new(s, s->samdb, (const char *)el->values[0].data);
136         if (!ldb_dn_validate(s->config_dn)) {
137                 return WERR_FOOBAR;
138         }
139
140         talloc_free(r);
141
142         return WERR_OK;
143 }
144
145
146 struct kcc_manual_runcmd_state {
147         struct irpc_message *msg;
148         struct drsuapi_DsExecuteKCC *r;
149         struct kccsrv_service *service;
150 };
151
152
153 /*
154  * Called when samba_kcc script has finished
155  */
156 static void manual_samba_kcc_done(struct tevent_req *subreq)
157 {
158         struct kcc_manual_runcmd_state *st =
159                 tevent_req_callback_data(subreq,
160                 struct kcc_manual_runcmd_state);
161         int rc;
162         int sys_errno;
163         NTSTATUS status;
164
165         st->service->periodic.subreq = NULL;
166
167         rc = samba_runcmd_recv(subreq, &sys_errno);
168         TALLOC_FREE(subreq);
169
170         if (rc != 0) {
171                 status = map_nt_error_from_unix_common(sys_errno);
172         } else {
173                 status = NT_STATUS_OK;
174         }
175
176         if (!NT_STATUS_IS_OK(status)) {
177                 DEBUG(0,(__location__ ": Failed manual run of samba_kcc - %s\n",
178                         nt_errstr(status)));
179         } else {
180                 DEBUG(3,("Completed manual run of samba_kcc OK\n"));
181         }
182
183         if (!(st->r->in.req->ctr1.flags & DRSUAPI_DS_EXECUTE_KCC_ASYNCHRONOUS_OPERATION)) {
184                 irpc_send_reply(st->msg, status);
185         }
186 }
187
188 static NTSTATUS kccsrv_execute_kcc(struct irpc_message *msg, struct drsuapi_DsExecuteKCC *r)
189 {
190         TALLOC_CTX *mem_ctx;
191         NTSTATUS status = NT_STATUS_OK;
192         struct kccsrv_service *service = talloc_get_type(msg->private_data, struct kccsrv_service);
193
194         const char * const *samba_kcc_command;
195         struct kcc_manual_runcmd_state *st;
196
197         if (!service->samba_kcc_code) {
198                 mem_ctx = talloc_new(service);
199
200                 status = kccsrv_simple_update(service, mem_ctx);
201                 if (!NT_STATUS_IS_OK(status)) {
202                         DEBUG(0,("kccsrv_execute_kcc failed - %s\n",
203                                 nt_errstr(status)));
204                 }
205                 talloc_free(mem_ctx);
206
207                 return NT_STATUS_OK;
208         }
209
210         /* Invocation of the samba_kcc python script for replication
211          * topology generation.
212          */
213
214         samba_kcc_command =
215                 lpcfg_samba_kcc_command(service->task->lp_ctx);
216
217         st = talloc(msg, struct kcc_manual_runcmd_state);
218         if (st == NULL) {
219                 return NT_STATUS_NO_MEMORY;
220         }
221
222         st->msg = msg;
223         st->r = r;
224         st->service = service;
225
226         /* don't run at the same time as an existing child */
227         if (service->periodic.subreq) {
228                 status = NT_STATUS_DS_BUSY;
229                 return status;
230         }
231
232         DEBUG(2, ("Calling samba_kcc script\n"));
233         service->periodic.subreq = samba_runcmd_send(service,
234                                                      service->task->event_ctx,
235                                                      timeval_current_ofs(40, 0),
236                                                      2, 0, samba_kcc_command, NULL);
237
238         if (service->periodic.subreq == NULL) {
239                 status = NT_STATUS_NO_MEMORY;
240                 DEBUG(0,(__location__ ": failed - %s\n", nt_errstr(status)));
241                 return status;
242         } else {
243                 tevent_req_set_callback(service->periodic.subreq,
244                                         manual_samba_kcc_done, st);
245         }
246
247         if (r->in.req->ctr1.flags & DRSUAPI_DS_EXECUTE_KCC_ASYNCHRONOUS_OPERATION) {
248                 /* This actually means reply right away, let it run in the background */
249         } else {
250                 /* mark the request as replied async, the caller wants to know when this is finished */
251                 msg->defer_reply = true;
252         }
253         return status;
254
255 }
256
257 static NTSTATUS kccsrv_replica_get_info(struct irpc_message *msg, struct drsuapi_DsReplicaGetInfo *r)
258 {
259         return kccdrs_replica_get_info(msg, r);
260 }
261
262 /*
263   startup the kcc service task
264 */
265 static void kccsrv_task_init(struct task_server *task)
266 {
267         WERROR status;
268         struct kccsrv_service *service;
269         uint32_t periodic_startup_interval;
270
271         switch (lpcfg_server_role(task->lp_ctx)) {
272         case ROLE_STANDALONE:
273                 task_server_terminate(task, "kccsrv: no KCC required in standalone configuration", false);
274                 return;
275         case ROLE_DOMAIN_MEMBER:
276                 task_server_terminate(task, "kccsrv: no KCC required in domain member configuration", false);
277                 return;
278         case ROLE_ACTIVE_DIRECTORY_DC:
279                 /* Yes, we want a KCC */
280                 break;
281         }
282
283         task_server_set_title(task, "task[kccsrv]");
284
285         service = talloc_zero(task, struct kccsrv_service);
286         if (!service) {
287                 task_server_terminate(task, "kccsrv_task_init: out of memory", true);
288                 return;
289         }
290         service->task           = task;
291         service->startup_time   = timeval_current();
292         task->private_data      = service;
293
294         status = kccsrv_init_creds(service);
295         if (!W_ERROR_IS_OK(status)) {
296                 task_server_terminate(task, 
297                                       talloc_asprintf(task,
298                                                       "kccsrv: Failed to obtain server credentials: %s\n",
299                                                       win_errstr(status)), true);
300                 return;
301         }
302
303         status = kccsrv_connect_samdb(service, task->lp_ctx);
304         if (!W_ERROR_IS_OK(status)) {
305                 task_server_terminate(task, talloc_asprintf(task,
306                                       "kccsrv: Failed to connect to local samdb: %s\n",
307                                                             win_errstr(status)), true);
308                 return;
309         }
310
311         status = kccsrv_load_partitions(service);
312         if (!W_ERROR_IS_OK(status)) {
313                 task_server_terminate(task, talloc_asprintf(task,
314                                       "kccsrv: Failed to load partitions: %s\n",
315                                                             win_errstr(status)), true);
316                 return;
317         }
318
319         periodic_startup_interval =
320                 lpcfg_parm_int(task->lp_ctx, NULL, "kccsrv",
321                               "periodic_startup_interval", 15); /* in seconds */
322         service->periodic.interval =
323                 lpcfg_parm_int(task->lp_ctx, NULL, "kccsrv",
324                               "periodic_interval", 300); /* in seconds */
325
326         /* (kccsrv:samba_kcc=true) will run newer samba_kcc replication
327          * topology generation code.
328          */
329         service->samba_kcc_code = lpcfg_parm_bool(task->lp_ctx, NULL,
330                                                 "kccsrv", "samba_kcc", true);
331
332         status = kccsrv_periodic_schedule(service, periodic_startup_interval);
333         if (!W_ERROR_IS_OK(status)) {
334                 task_server_terminate(task, talloc_asprintf(task,
335                                       "kccsrv: Failed to periodic schedule: %s\n",
336                                                             win_errstr(status)), true);
337                 return;
338         }
339
340         irpc_add_name(task->msg_ctx, "kccsrv");
341
342         IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSEXECUTEKCC, kccsrv_execute_kcc, service);
343         IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICAGETINFO, kccsrv_replica_get_info, service);
344 }
345
346 /*
347   register ourselves as a available server
348 */
349 NTSTATUS server_service_kcc_init(void)
350 {
351         return register_server_service("kcc", kccsrv_task_init);
352 }