Line data Source code
1 : /*
2 : Unix SMB/CIFS Implementation.
3 :
4 : DNS update service
5 :
6 : Copyright (C) Andrew Tridgell 2009
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 :
21 : */
22 :
23 : /*
24 : this module auto-creates the named.conf.update file, which tells
25 : bind9 what KRB5 principals it should accept for updates to our zone
26 :
27 : It also uses the samba_dnsupdate script to auto-create the right DNS
28 : names for ourselves as a DC in the domain, using TSIG-GSS
29 : */
30 :
31 : #include "includes.h"
32 : #include "dsdb/samdb/samdb.h"
33 : #include "auth/auth.h"
34 : #include "samba/service.h"
35 : #include "lib/messaging/irpc.h"
36 : #include "param/param.h"
37 : #include "system/filesys.h"
38 : #include "dsdb/common/util.h"
39 : #include "libcli/composite/composite.h"
40 : #include "libcli/security/dom_sid.h"
41 : #include "librpc/gen_ndr/ndr_irpc.h"
42 : #include "libds/common/roles.h"
43 :
44 : NTSTATUS server_service_dnsupdate_init(TALLOC_CTX *);
45 :
46 : struct dnsupdate_service {
47 : struct task_server *task;
48 : struct auth_session_info *system_session_info;
49 : struct ldb_context *samdb;
50 :
51 : /* status for periodic config file update */
52 : struct {
53 : uint32_t interval;
54 : struct tevent_timer *te;
55 : struct tevent_req *subreq;
56 : NTSTATUS status;
57 : } confupdate;
58 :
59 : /* status for periodic DNS name check */
60 : struct {
61 : uint32_t interval;
62 : struct tevent_timer *te;
63 : struct tevent_req *subreq;
64 : struct tevent_req *spnreq;
65 : NTSTATUS status;
66 : } nameupdate;
67 : };
68 :
69 : /*
70 : called when dns update script has finished
71 : */
72 118 : static void dnsupdate_nameupdate_done(struct tevent_req *subreq)
73 : {
74 118 : struct dnsupdate_service *service = tevent_req_callback_data(subreq,
75 : struct dnsupdate_service);
76 2 : int ret;
77 2 : int sys_errno;
78 :
79 118 : service->nameupdate.subreq = NULL;
80 :
81 118 : ret = samba_runcmd_recv(subreq, &sys_errno);
82 118 : TALLOC_FREE(subreq);
83 :
84 118 : if (ret != 0) {
85 1 : DBG_ERR("Failed DNS update with exit code %d\n",
86 : sys_errno);
87 : } else {
88 117 : DEBUG(3,("Completed DNS update check OK\n"));
89 : }
90 118 : }
91 :
92 :
93 : /*
94 : called when spn update script has finished
95 : */
96 118 : static void dnsupdate_spnupdate_done(struct tevent_req *subreq)
97 : {
98 118 : struct dnsupdate_service *service = tevent_req_callback_data(subreq,
99 : struct dnsupdate_service);
100 2 : int ret;
101 2 : int sys_errno;
102 :
103 118 : service->nameupdate.spnreq = NULL;
104 :
105 118 : ret = samba_runcmd_recv(subreq, &sys_errno);
106 118 : TALLOC_FREE(subreq);
107 118 : if (ret != 0) {
108 0 : DEBUG(0,(__location__ ": Failed SPN update - with error code %d\n",
109 : sys_errno));
110 : } else {
111 118 : DEBUG(3,("Completed SPN update check OK\n"));
112 : }
113 118 : }
114 :
115 : /*
116 : called every 'dnsupdate:name interval' seconds
117 : */
118 118 : static void dnsupdate_check_names(struct dnsupdate_service *service)
119 : {
120 118 : const char * const *dns_update_command = lpcfg_dns_update_command(service->task->lp_ctx);
121 118 : const char * const *spn_update_command = lpcfg_spn_update_command(service->task->lp_ctx);
122 :
123 : /* kill any existing child */
124 118 : TALLOC_FREE(service->nameupdate.subreq);
125 :
126 118 : DEBUG(3,("Calling DNS name update script\n"));
127 118 : service->nameupdate.subreq = samba_runcmd_send(service,
128 118 : service->task->event_ctx,
129 : timeval_current_ofs(20, 0),
130 : 2, 0,
131 : dns_update_command,
132 : NULL);
133 118 : if (service->nameupdate.subreq == NULL) {
134 0 : DEBUG(0,(__location__ ": samba_runcmd_send() failed with no memory\n"));
135 0 : return;
136 : }
137 118 : tevent_req_set_callback(service->nameupdate.subreq,
138 : dnsupdate_nameupdate_done,
139 : service);
140 :
141 118 : DEBUG(3,("Calling SPN name update script\n"));
142 118 : service->nameupdate.spnreq = samba_runcmd_send(service,
143 118 : service->task->event_ctx,
144 : timeval_current_ofs(20, 0),
145 : 2, 0,
146 : spn_update_command,
147 : NULL);
148 118 : if (service->nameupdate.spnreq == NULL) {
149 0 : DEBUG(0,(__location__ ": samba_runcmd_send() failed with no memory\n"));
150 0 : return;
151 : }
152 118 : tevent_req_set_callback(service->nameupdate.spnreq,
153 : dnsupdate_spnupdate_done,
154 : service);
155 : }
156 :
157 : static NTSTATUS dnsupdate_nameupdate_schedule(struct dnsupdate_service *service);
158 :
159 : /*
160 : called every 'dnsupdate:name interval' seconds
161 : */
162 59 : static void dnsupdate_nameupdate_handler_te(struct tevent_context *ev, struct tevent_timer *te,
163 : struct timeval t, void *ptr)
164 : {
165 59 : struct dnsupdate_service *service = talloc_get_type(ptr, struct dnsupdate_service);
166 :
167 59 : dnsupdate_check_names(service);
168 59 : dnsupdate_nameupdate_schedule(service);
169 59 : }
170 :
171 :
172 118 : static NTSTATUS dnsupdate_nameupdate_schedule(struct dnsupdate_service *service)
173 : {
174 118 : service->nameupdate.te = tevent_add_timer(service->task->event_ctx, service,
175 : timeval_current_ofs(service->nameupdate.interval, 0),
176 : dnsupdate_nameupdate_handler_te, service);
177 118 : NT_STATUS_HAVE_NO_MEMORY(service->nameupdate.te);
178 118 : return NT_STATUS_OK;
179 : }
180 :
181 :
182 : struct dnsupdate_RODC_state {
183 : struct irpc_message *msg;
184 : struct dnsupdate_RODC *r;
185 : char *tmp_path;
186 : char *tmp_path2;
187 : int fd;
188 : };
189 :
190 5 : static int dnsupdate_RODC_destructor(struct dnsupdate_RODC_state *st)
191 : {
192 5 : if (st->fd != -1) {
193 0 : close(st->fd);
194 : }
195 5 : unlink(st->tmp_path);
196 5 : if (st->tmp_path2 != NULL) {
197 5 : unlink(st->tmp_path2);
198 : }
199 5 : return 0;
200 : }
201 :
202 : /*
203 : called when the DNS update has completed
204 : */
205 5 : static void dnsupdate_RODC_callback(struct tevent_req *req)
206 : {
207 0 : struct dnsupdate_RODC_state *st =
208 5 : tevent_req_callback_data(req,
209 : struct dnsupdate_RODC_state);
210 0 : int sys_errno;
211 0 : int i, ret;
212 :
213 5 : ret = samba_runcmd_recv(req, &sys_errno);
214 5 : talloc_free(req);
215 5 : if (ret != 0) {
216 0 : st->r->out.result = map_nt_error_from_unix_common(sys_errno);
217 0 : DEBUG(2,(__location__ ": RODC DNS Update failed: %s\n", nt_errstr(st->r->out.result)));
218 : } else {
219 5 : st->r->out.result = NT_STATUS_OK;
220 5 : DEBUG(3,(__location__ ": RODC DNS Update OK\n"));
221 : }
222 :
223 10 : for (i=0; i<st->r->in.dns_names->count; i++) {
224 5 : st->r->out.dns_names->names[i].status = NT_STATUS_V(st->r->out.result);
225 : }
226 :
227 5 : irpc_send_reply(st->msg, NT_STATUS_OK);
228 5 : }
229 :
230 :
231 : /**
232 : * Called when we get a RODC DNS update request from the netlogon
233 : * rpc server
234 : */
235 5 : static NTSTATUS dnsupdate_dnsupdate_RODC(struct irpc_message *msg,
236 : struct dnsupdate_RODC *r)
237 : {
238 5 : struct dnsupdate_service *s = talloc_get_type(msg->private_data,
239 : struct dnsupdate_service);
240 5 : const char * const *dns_update_command = lpcfg_dns_update_command(s->task->lp_ctx);
241 0 : struct dnsupdate_RODC_state *st;
242 0 : struct tevent_req *req;
243 0 : int i, ret;
244 0 : struct GUID ntds_guid;
245 0 : const char *site, *dnsdomain, *dnsforest, *ntdsguid;
246 5 : const char *hostname = NULL;
247 0 : struct ldb_dn *sid_dn;
248 5 : const char *attrs[] = { "dNSHostName", NULL };
249 0 : struct ldb_result *res;
250 :
251 5 : st = talloc_zero(msg, struct dnsupdate_RODC_state);
252 5 : if (!st) {
253 0 : r->out.result = NT_STATUS_NO_MEMORY;
254 0 : return NT_STATUS_OK;
255 : }
256 :
257 5 : st->r = r;
258 5 : st->msg = msg;
259 :
260 5 : st->tmp_path = smbd_tmp_path(st, s->task->lp_ctx, "rodcdns.XXXXXX");
261 5 : if (!st->tmp_path) {
262 0 : talloc_free(st);
263 0 : r->out.result = NT_STATUS_NO_MEMORY;
264 0 : return NT_STATUS_OK;
265 : }
266 :
267 5 : st->fd = mkstemp(st->tmp_path);
268 5 : if (st->fd == -1) {
269 0 : DEBUG(0,("Unable to create a temporary file for RODC dnsupdate\n"));
270 0 : talloc_free(st);
271 0 : r->out.result = NT_STATUS_INTERNAL_DB_CORRUPTION;
272 0 : return NT_STATUS_OK;
273 : }
274 :
275 5 : talloc_set_destructor(st, dnsupdate_RODC_destructor);
276 :
277 5 : st->tmp_path2 = talloc_asprintf(st, "%s.cache", st->tmp_path);
278 5 : if (!st->tmp_path2) {
279 0 : talloc_free(st);
280 0 : r->out.result = NT_STATUS_NO_MEMORY;
281 0 : return NT_STATUS_OK;
282 : }
283 :
284 5 : sid_dn = ldb_dn_new_fmt(st, s->samdb, "<SID=%s>", dom_sid_string(st, r->in.dom_sid));
285 5 : if (!sid_dn) {
286 0 : talloc_free(st);
287 0 : r->out.result = NT_STATUS_NO_MEMORY;
288 0 : return NT_STATUS_OK;
289 : }
290 :
291 : /* work out the site */
292 5 : ret = samdb_find_site_for_computer(s->samdb, st, sid_dn, &site);
293 5 : if (ret != LDB_SUCCESS) {
294 0 : DEBUG(2, (__location__ ": Unable to find site for computer %s\n",
295 : ldb_dn_get_linearized(sid_dn)));
296 0 : talloc_free(st);
297 0 : r->out.result = NT_STATUS_NO_SUCH_USER;
298 0 : return NT_STATUS_OK;
299 : }
300 :
301 : /* work out the ntdsguid */
302 5 : ret = samdb_find_ntdsguid_for_computer(s->samdb, sid_dn, &ntds_guid);
303 5 : ntdsguid = GUID_string(st, &ntds_guid);
304 5 : if (ret != LDB_SUCCESS || !ntdsguid) {
305 0 : DEBUG(2, (__location__ ": Unable to find NTDS GUID for computer %s\n",
306 : ldb_dn_get_linearized(sid_dn)));
307 0 : talloc_free(st);
308 0 : r->out.result = NT_STATUS_NO_SUCH_USER;
309 0 : return NT_STATUS_OK;
310 : }
311 :
312 :
313 : /* find dnsdomain and dnsforest */
314 5 : dnsdomain = lpcfg_dnsdomain(s->task->lp_ctx);
315 5 : dnsforest = dnsdomain;
316 :
317 : /* find the hostname */
318 5 : ret = dsdb_search_dn(s->samdb, st, &res, sid_dn, attrs, 0);
319 5 : if (ret == LDB_SUCCESS) {
320 5 : hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
321 : }
322 5 : if (ret != LDB_SUCCESS || !hostname) {
323 0 : DEBUG(2, (__location__ ": Unable to find NTDS GUID for computer %s\n",
324 : ldb_dn_get_linearized(sid_dn)));
325 0 : talloc_free(st);
326 0 : r->out.result = NT_STATUS_NO_SUCH_USER;
327 0 : return NT_STATUS_OK;
328 : }
329 :
330 10 : for (i=0; i<st->r->in.dns_names->count; i++) {
331 5 : struct NL_DNS_NAME_INFO *n = &r->in.dns_names->names[i];
332 5 : switch (n->type) {
333 1 : case NlDnsLdapAtSite:
334 1 : dprintf(st->fd, "SRV _ldap._tcp.%s._sites.%s %s %u\n",
335 : site, dnsdomain, hostname, n->port);
336 1 : break;
337 0 : case NlDnsGcAtSite:
338 0 : dprintf(st->fd, "SRV _ldap._tcp.%s._sites.gc._msdcs.%s %s %u\n",
339 : site, dnsdomain, hostname, n->port);
340 0 : break;
341 1 : case NlDnsDsaCname:
342 1 : dprintf(st->fd, "CNAME %s._msdcs.%s %s\n",
343 : ntdsguid, dnsforest, hostname);
344 1 : break;
345 1 : case NlDnsKdcAtSite:
346 1 : dprintf(st->fd, "SRV _kerberos._tcp.%s._sites.dc._msdcs.%s %s %u\n",
347 : site, dnsdomain, hostname, n->port);
348 1 : break;
349 1 : case NlDnsDcAtSite:
350 1 : dprintf(st->fd, "SRV _ldap._tcp.%s._sites.dc._msdcs.%s %s %u\n",
351 : site, dnsdomain, hostname, n->port);
352 1 : break;
353 1 : case NlDnsRfc1510KdcAtSite:
354 1 : dprintf(st->fd, "SRV _kerberos._tcp.%s._sites.%s %s %u\n",
355 : site, dnsdomain, hostname, n->port);
356 1 : break;
357 0 : case NlDnsGenericGcAtSite:
358 0 : dprintf(st->fd, "SRV _gc._tcp.%s._sites.%s %s %u\n",
359 : site, dnsforest, hostname, n->port);
360 0 : break;
361 : }
362 : }
363 :
364 5 : close(st->fd);
365 5 : st->fd = -1;
366 :
367 5 : DEBUG(3,("Calling RODC DNS name update script %s\n", st->tmp_path));
368 5 : req = samba_runcmd_send(st,
369 5 : s->task->event_ctx,
370 : timeval_current_ofs(20, 0),
371 : 2, 0,
372 : dns_update_command,
373 : "--update-list",
374 : st->tmp_path,
375 : "--update-cache",
376 : st->tmp_path2,
377 : NULL);
378 5 : NT_STATUS_HAVE_NO_MEMORY(req);
379 :
380 : /* setup the callback */
381 5 : tevent_req_set_callback(req, dnsupdate_RODC_callback, st);
382 :
383 5 : msg->defer_reply = true;
384 :
385 5 : return NT_STATUS_OK;
386 : }
387 :
388 : /*
389 : startup the dns update task
390 : */
391 65 : static NTSTATUS dnsupdate_task_init(struct task_server *task)
392 : {
393 2 : NTSTATUS status;
394 2 : struct dnsupdate_service *service;
395 :
396 65 : if (lpcfg_server_role(task->lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
397 : /* not useful for non-DC */
398 6 : return NT_STATUS_INVALID_DOMAIN_ROLE;
399 : }
400 :
401 59 : task_server_set_title(task, "task[dnsupdate]");
402 :
403 59 : service = talloc_zero(task, struct dnsupdate_service);
404 59 : if (!service) {
405 0 : task_server_terminate(task, "dnsupdate_task_init: out of memory", true);
406 0 : return NT_STATUS_NO_MEMORY;
407 : }
408 59 : service->task = task;
409 59 : task->private_data = service;
410 :
411 59 : service->system_session_info = system_session(service->task->lp_ctx);
412 59 : if (!service->system_session_info) {
413 0 : task_server_terminate(task,
414 : "dnsupdate: Failed to obtain server credentials\n",
415 : true);
416 0 : return NT_STATUS_UNSUCCESSFUL;
417 : }
418 :
419 118 : service->samdb = samdb_connect(service,
420 59 : service->task->event_ctx,
421 : task->lp_ctx,
422 : service->system_session_info,
423 : NULL,
424 : 0);
425 59 : if (!service->samdb) {
426 0 : task_server_terminate(task, "dnsupdate: Failed to connect to local samdb\n",
427 : true);
428 0 : return NT_STATUS_UNSUCCESSFUL;
429 : }
430 :
431 59 : service->nameupdate.interval = lpcfg_parm_int(task->lp_ctx, NULL,
432 : "dnsupdate", "name interval", 600); /* in seconds */
433 :
434 59 : dnsupdate_check_names(service);
435 59 : status = dnsupdate_nameupdate_schedule(service);
436 59 : if (!NT_STATUS_IS_OK(status)) {
437 0 : task_server_terminate(task, talloc_asprintf(task,
438 : "dnsupdate: Failed to nameupdate schedule: %s\n",
439 : nt_errstr(status)), true);
440 0 : return status;
441 : }
442 :
443 59 : irpc_add_name(task->msg_ctx, "dnsupdate");
444 :
445 59 : IRPC_REGISTER(task->msg_ctx, irpc, DNSUPDATE_RODC,
446 : dnsupdate_dnsupdate_RODC, service);
447 :
448 59 : return NT_STATUS_OK;
449 :
450 : }
451 :
452 : /*
453 : register ourselves as a available server
454 : */
455 66 : NTSTATUS server_service_dnsupdate_init(TALLOC_CTX *ctx)
456 : {
457 3 : static const struct service_details details = {
458 : .inhibit_fork_on_accept = true,
459 : .inhibit_pre_fork = true,
460 : .task_init = dnsupdate_task_init,
461 : .post_fork = NULL
462 : };
463 66 : return register_server_service(ctx, "dnsupdate", &details);
464 : }
|