2 Unix SMB/CIFS mplementation.
6 Copyright (C) Andrew Tridgell 2009
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.
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.
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/>.
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
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
32 #include "dsdb/samdb/samdb.h"
33 #include "auth/auth.h"
34 #include "smbd/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"
43 NTSTATUS
server_service_dnsupdate_init(void);
45 struct dnsupdate_service
{
46 struct task_server
*task
;
47 struct auth_session_info
*system_session_info
;
48 struct ldb_context
*samdb
;
50 /* status for periodic config file update */
53 struct tevent_timer
*te
;
54 struct tevent_req
*subreq
;
58 /* status for periodic DNS name check */
61 struct tevent_timer
*te
;
62 struct tevent_req
*subreq
;
63 struct tevent_req
*spnreq
;
69 called when rndc reload has finished
71 static void dnsupdate_rndc_done(struct tevent_req
*subreq
)
73 struct dnsupdate_service
*service
= tevent_req_callback_data(subreq
,
74 struct dnsupdate_service
);
78 service
->confupdate
.subreq
= NULL
;
80 ret
= samba_runcmd_recv(subreq
, &sys_errno
);
83 service
->confupdate
.status
= map_nt_error_from_unix_common(sys_errno
);
85 service
->confupdate
.status
= NT_STATUS_OK
;
88 if (!NT_STATUS_IS_OK(service
->confupdate
.status
)) {
89 DEBUG(0,(__location__
": Failed rndc update - %s\n",
90 nt_errstr(service
->confupdate
.status
)));
92 DEBUG(3,("Completed rndc reload OK\n"));
97 called every 'dnsupdate:conf interval' seconds
99 static void dnsupdate_rebuild(struct dnsupdate_service
*service
)
103 struct ldb_result
*res1
, *res2
;
104 const char *tmp_path
, *path
, *path_static
;
105 char *static_policies
;
108 const char *attrs1
[] = { "msDS-HasDomainNCs", NULL
};
109 const char *attrs2
[] = { "name", NULL
};
110 const char *realm
= lpcfg_realm(service
->task
->lp_ctx
);
111 TALLOC_CTX
*tmp_ctx
= talloc_new(service
);
112 const char * const *rndc_command
= lpcfg_rndc_command(service
->task
->lp_ctx
);
113 const char **dc_list
;
116 /* abort any pending script run */
117 TALLOC_FREE(service
->confupdate
.subreq
);
119 /* find the DNs for all the non-RODC DCs in the forest */
120 ret
= dsdb_search(service
->samdb
, tmp_ctx
, &res1
, ldb_get_config_basedn(service
->samdb
),
124 "(&(objectclass=NTDSDSA)(!(msDS-isRODC=TRUE)))");
125 if (ret
!= LDB_SUCCESS
) {
126 DEBUG(0,(__location__
": Unable to find DCs list - %s", ldb_errstring(service
->samdb
)));
127 talloc_free(tmp_ctx
);
131 dc_list
= talloc_array(tmp_ctx
, const char *, 0);
132 for (i
=0; i
<res1
->count
; i
++) {
133 struct ldb_dn
*server_dn
= res1
->msgs
[i
]->dn
;
134 struct ldb_dn
*domain_dn
;
135 const char *acct_name
, *full_account
, *dns_domain
;
137 /* this is a nasty hack to form the account name of
138 * this DC. We do it this way as we don't necessarily
139 * have access to the domain NC, so all we have to go
140 * on is what is in the configuration partition
143 domain_dn
= ldb_msg_find_attr_as_dn(service
->samdb
, tmp_ctx
, res1
->msgs
[i
], "msDS-HasDomainNCs");
144 if (domain_dn
== NULL
) continue;
146 ldb_dn_remove_child_components(server_dn
, 1);
147 ret
= dsdb_search_dn(service
->samdb
, tmp_ctx
, &res2
, server_dn
, attrs2
, 0);
148 if (ret
!= LDB_SUCCESS
) {
152 acct_name
= ldb_msg_find_attr_as_string(res2
->msgs
[0], "name", NULL
);
153 if (acct_name
== NULL
) continue;
155 dns_domain
= samdb_dn_to_dns_domain(tmp_ctx
, domain_dn
);
156 if (dns_domain
== NULL
) {
160 full_account
= talloc_asprintf(tmp_ctx
, "%s$@%s", acct_name
, dns_domain
);
161 if (full_account
== NULL
) continue;
163 dc_list
= talloc_realloc(tmp_ctx
, dc_list
, const char *, dc_count
+1);
164 if (dc_list
== NULL
) {
167 dc_list
[dc_count
++] = full_account
;
170 path
= lpcfg_parm_string(service
->task
->lp_ctx
, NULL
, "dnsupdate", "path");
172 path
= lpcfg_private_path(tmp_ctx
, service
->task
->lp_ctx
, "named.conf.update");
175 path_static
= lpcfg_parm_string(service
->task
->lp_ctx
, NULL
, "dnsupdate", "extra_static_grant_rules");
176 if (path_static
== NULL
) {
177 path_static
= lpcfg_private_path(tmp_ctx
, service
->task
->lp_ctx
, "named.conf.update.static");
180 tmp_path
= talloc_asprintf(tmp_ctx
, "%s.tmp", path
);
181 if (path
== NULL
|| tmp_path
== NULL
|| path_static
== NULL
) {
182 DEBUG(0,(__location__
": Unable to get paths\n"));
183 talloc_free(tmp_ctx
);
187 static_policies
= file_load(path_static
, &size
, 0, tmp_ctx
);
190 fd
= open(tmp_path
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0444);
192 DEBUG(1,(__location__
": Unable to open %s - %s\n", tmp_path
, strerror(errno
)));
193 talloc_free(tmp_ctx
);
197 dprintf(fd
, "/* this file is auto-generated - do not edit */\n");
198 dprintf(fd
, "update-policy {\n");
199 if( static_policies
!= NULL
) {
200 dprintf(fd
, "/* Start of static entries */\n");
201 dprintf(fd
, "%s\n",static_policies
);
202 dprintf(fd
, "/* End of static entries */\n");
204 dprintf(fd
, "\tgrant %s ms-self * A AAAA;\n", realm
);
205 dprintf(fd
, "\tgrant Administrator@%s wildcard * A AAAA SRV CNAME;\n", realm
);
207 for (i
=0; i
<dc_count
; i
++) {
208 dprintf(fd
, "\tgrant %s wildcard * A AAAA SRV CNAME;\n", dc_list
[i
]);
214 if (NT_STATUS_IS_OK(service
->confupdate
.status
) &&
215 file_compare(tmp_path
, path
) == true) {
217 talloc_free(tmp_ctx
);
221 if (rename(tmp_path
, path
) != 0) {
222 DEBUG(0,(__location__
": Failed to rename %s to %s - %s\n",
223 tmp_path
, path
, strerror(errno
)));
224 talloc_free(tmp_ctx
);
228 DEBUG(2,("Loading new DNS update grant rules\n"));
229 service
->confupdate
.subreq
= samba_runcmd_send(service
,
230 service
->task
->event_ctx
,
231 timeval_current_ofs(10, 0),
235 if (service
->confupdate
.subreq
== NULL
) {
236 DEBUG(0,(__location__
": samba_runcmd_send() failed with no memory\n"));
237 talloc_free(tmp_ctx
);
240 tevent_req_set_callback(service
->confupdate
.subreq
,
244 talloc_free(tmp_ctx
);
247 static NTSTATUS
dnsupdate_confupdate_schedule(struct dnsupdate_service
*service
);
250 called every 'dnsupdate:conf interval' seconds
252 static void dnsupdate_confupdate_handler_te(struct tevent_context
*ev
, struct tevent_timer
*te
,
253 struct timeval t
, void *ptr
)
255 struct dnsupdate_service
*service
= talloc_get_type(ptr
, struct dnsupdate_service
);
257 dnsupdate_rebuild(service
);
258 dnsupdate_confupdate_schedule(service
);
262 static NTSTATUS
dnsupdate_confupdate_schedule(struct dnsupdate_service
*service
)
264 service
->confupdate
.te
= tevent_add_timer(service
->task
->event_ctx
, service
,
265 timeval_current_ofs(service
->confupdate
.interval
, 0),
266 dnsupdate_confupdate_handler_te
, service
);
267 NT_STATUS_HAVE_NO_MEMORY(service
->confupdate
.te
);
273 called when dns update script has finished
275 static void dnsupdate_nameupdate_done(struct tevent_req
*subreq
)
277 struct dnsupdate_service
*service
= tevent_req_callback_data(subreq
,
278 struct dnsupdate_service
);
282 service
->nameupdate
.subreq
= NULL
;
284 ret
= samba_runcmd_recv(subreq
, &sys_errno
);
287 service
->nameupdate
.status
= map_nt_error_from_unix_common(sys_errno
);
289 service
->nameupdate
.status
= NT_STATUS_OK
;
292 if (!NT_STATUS_IS_OK(service
->nameupdate
.status
)) {
293 DEBUG(0,(__location__
": Failed DNS update - %s\n",
294 nt_errstr(service
->nameupdate
.status
)));
296 DEBUG(3,("Completed DNS update check OK\n"));
302 called when spn update script has finished
304 static void dnsupdate_spnupdate_done(struct tevent_req
*subreq
)
306 struct dnsupdate_service
*service
= tevent_req_callback_data(subreq
,
307 struct dnsupdate_service
);
311 service
->nameupdate
.spnreq
= NULL
;
313 ret
= samba_runcmd_recv(subreq
, &sys_errno
);
316 service
->nameupdate
.status
= map_nt_error_from_unix_common(sys_errno
);
318 service
->nameupdate
.status
= NT_STATUS_OK
;
321 if (!NT_STATUS_IS_OK(service
->nameupdate
.status
)) {
322 DEBUG(0,(__location__
": Failed SPN update - %s\n",
323 nt_errstr(service
->nameupdate
.status
)));
325 DEBUG(3,("Completed SPN update check OK\n"));
330 called every 'dnsupdate:name interval' seconds
332 static void dnsupdate_check_names(struct dnsupdate_service
*service
)
334 const char * const *dns_update_command
= lpcfg_dns_update_command(service
->task
->lp_ctx
);
335 const char * const *spn_update_command
= lpcfg_spn_update_command(service
->task
->lp_ctx
);
337 /* kill any existing child */
338 TALLOC_FREE(service
->nameupdate
.subreq
);
340 DEBUG(3,("Calling DNS name update script\n"));
341 service
->nameupdate
.subreq
= samba_runcmd_send(service
,
342 service
->task
->event_ctx
,
343 timeval_current_ofs(20, 0),
347 if (service
->nameupdate
.subreq
== NULL
) {
348 DEBUG(0,(__location__
": samba_runcmd_send() failed with no memory\n"));
351 tevent_req_set_callback(service
->nameupdate
.subreq
,
352 dnsupdate_nameupdate_done
,
355 DEBUG(3,("Calling SPN name update script\n"));
356 service
->nameupdate
.spnreq
= samba_runcmd_send(service
,
357 service
->task
->event_ctx
,
358 timeval_current_ofs(20, 0),
362 if (service
->nameupdate
.spnreq
== NULL
) {
363 DEBUG(0,(__location__
": samba_runcmd_send() failed with no memory\n"));
366 tevent_req_set_callback(service
->nameupdate
.spnreq
,
367 dnsupdate_spnupdate_done
,
371 static NTSTATUS
dnsupdate_nameupdate_schedule(struct dnsupdate_service
*service
);
374 called every 'dnsupdate:name interval' seconds
376 static void dnsupdate_nameupdate_handler_te(struct tevent_context
*ev
, struct tevent_timer
*te
,
377 struct timeval t
, void *ptr
)
379 struct dnsupdate_service
*service
= talloc_get_type(ptr
, struct dnsupdate_service
);
381 dnsupdate_check_names(service
);
382 dnsupdate_nameupdate_schedule(service
);
386 static NTSTATUS
dnsupdate_nameupdate_schedule(struct dnsupdate_service
*service
)
388 service
->nameupdate
.te
= tevent_add_timer(service
->task
->event_ctx
, service
,
389 timeval_current_ofs(service
->nameupdate
.interval
, 0),
390 dnsupdate_nameupdate_handler_te
, service
);
391 NT_STATUS_HAVE_NO_MEMORY(service
->nameupdate
.te
);
396 struct dnsupdate_RODC_state
{
397 struct irpc_message
*msg
;
398 struct dnsupdate_RODC
*r
;
404 static int dnsupdate_RODC_destructor(struct dnsupdate_RODC_state
*st
)
409 unlink(st
->tmp_path
);
410 if (st
->tmp_path2
!= NULL
) {
411 unlink(st
->tmp_path2
);
417 called when the DNS update has completed
419 static void dnsupdate_RODC_callback(struct tevent_req
*req
)
421 struct dnsupdate_RODC_state
*st
=
422 tevent_req_callback_data(req
,
423 struct dnsupdate_RODC_state
);
427 ret
= samba_runcmd_recv(req
, &sys_errno
);
430 st
->r
->out
.result
= map_nt_error_from_unix_common(sys_errno
);
431 DEBUG(2,(__location__
": RODC DNS Update failed: %s\n", nt_errstr(st
->r
->out
.result
)));
433 st
->r
->out
.result
= NT_STATUS_OK
;
434 DEBUG(3,(__location__
": RODC DNS Update OK\n"));
437 for (i
=0; i
<st
->r
->in
.dns_names
->count
; i
++) {
438 st
->r
->out
.dns_names
->names
[i
].status
= NT_STATUS_V(st
->r
->out
.result
);
441 irpc_send_reply(st
->msg
, NT_STATUS_OK
);
446 * Called when we get a RODC DNS update request from the netlogon
449 static NTSTATUS
dnsupdate_dnsupdate_RODC(struct irpc_message
*msg
,
450 struct dnsupdate_RODC
*r
)
452 struct dnsupdate_service
*s
= talloc_get_type(msg
->private_data
,
453 struct dnsupdate_service
);
454 const char * const *dns_update_command
= lpcfg_dns_update_command(s
->task
->lp_ctx
);
455 struct dnsupdate_RODC_state
*st
;
456 struct tevent_req
*req
;
458 struct GUID ntds_guid
;
459 const char *site
, *dnsdomain
, *dnsforest
, *ntdsguid
, *hostname
;
460 struct ldb_dn
*sid_dn
;
461 const char *attrs
[] = { "dNSHostName", NULL
};
462 struct ldb_result
*res
;
464 st
= talloc_zero(msg
, struct dnsupdate_RODC_state
);
466 r
->out
.result
= NT_STATUS_NO_MEMORY
;
473 st
->tmp_path
= smbd_tmp_path(st
, s
->task
->lp_ctx
, "rodcdns.XXXXXX");
476 r
->out
.result
= NT_STATUS_NO_MEMORY
;
480 st
->fd
= mkstemp(st
->tmp_path
);
482 DEBUG(0,("Unable to create a temporary file for RODC dnsupdate\n"));
484 r
->out
.result
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
488 talloc_set_destructor(st
, dnsupdate_RODC_destructor
);
490 st
->tmp_path2
= talloc_asprintf(st
, "%s.cache", st
->tmp_path
);
491 if (!st
->tmp_path2
) {
493 r
->out
.result
= NT_STATUS_NO_MEMORY
;
497 sid_dn
= ldb_dn_new_fmt(st
, s
->samdb
, "<SID=%s>", dom_sid_string(st
, r
->in
.dom_sid
));
500 r
->out
.result
= NT_STATUS_NO_MEMORY
;
504 /* work out the site */
505 ret
= samdb_find_site_for_computer(s
->samdb
, st
, sid_dn
, &site
);
506 if (ret
!= LDB_SUCCESS
) {
507 DEBUG(2, (__location__
": Unable to find site for computer %s\n",
508 ldb_dn_get_linearized(sid_dn
)));
510 r
->out
.result
= NT_STATUS_NO_SUCH_USER
;
514 /* work out the ntdsguid */
515 ret
= samdb_find_ntdsguid_for_computer(s
->samdb
, sid_dn
, &ntds_guid
);
516 ntdsguid
= GUID_string(st
, &ntds_guid
);
517 if (ret
!= LDB_SUCCESS
|| !ntdsguid
) {
518 DEBUG(2, (__location__
": Unable to find NTDS GUID for computer %s\n",
519 ldb_dn_get_linearized(sid_dn
)));
521 r
->out
.result
= NT_STATUS_NO_SUCH_USER
;
526 /* find dnsdomain and dnsforest */
527 dnsdomain
= lpcfg_realm(s
->task
->lp_ctx
);
528 dnsforest
= dnsdomain
;
530 /* find the hostname */
531 ret
= dsdb_search_dn(s
->samdb
, st
, &res
, sid_dn
, attrs
, 0);
532 if (ret
== LDB_SUCCESS
) {
533 hostname
= ldb_msg_find_attr_as_string(res
->msgs
[0], "dNSHostName", NULL
);
535 if (ret
!= LDB_SUCCESS
|| !hostname
) {
536 DEBUG(2, (__location__
": Unable to find NTDS GUID for computer %s\n",
537 ldb_dn_get_linearized(sid_dn
)));
539 r
->out
.result
= NT_STATUS_NO_SUCH_USER
;
544 for (i
=0; i
<st
->r
->in
.dns_names
->count
; i
++) {
545 struct NL_DNS_NAME_INFO
*n
= &r
->in
.dns_names
->names
[i
];
547 case NlDnsLdapAtSite
:
548 dprintf(st
->fd
, "SRV _ldap._tcp.%s._sites.%s. %s %u\n",
549 site
, dnsdomain
, hostname
, n
->port
);
552 dprintf(st
->fd
, "SRV _ldap._tcp.%s._sites.gc._msdcs.%s. %s %u\n",
553 site
, dnsdomain
, hostname
, n
->port
);
556 dprintf(st
->fd
, "CNAME %s._msdcs.%s. %s\n",
557 ntdsguid
, dnsforest
, hostname
);
560 dprintf(st
->fd
, "SRV _kerberos._tcp.%s._sites.dc._msdcs.%s. %s %u\n",
561 site
, dnsdomain
, hostname
, n
->port
);
564 dprintf(st
->fd
, "SRV _ldap._tcp.%s._sites.dc._msdcs.%s. %s %u\n",
565 site
, dnsdomain
, hostname
, n
->port
);
567 case NlDnsRfc1510KdcAtSite
:
568 dprintf(st
->fd
, "SRV _kerberos._tcp.%s._sites.%s. %s %u\n",
569 site
, dnsdomain
, hostname
, n
->port
);
571 case NlDnsGenericGcAtSite
:
572 dprintf(st
->fd
, "SRV _gc._tcp.%s._sites.%s. %s %u\n",
573 site
, dnsforest
, hostname
, n
->port
);
581 DEBUG(3,("Calling RODC DNS name update script %s\n", st
->tmp_path
));
582 req
= samba_runcmd_send(st
,
584 timeval_current_ofs(20, 0),
592 NT_STATUS_HAVE_NO_MEMORY(req
);
594 /* setup the callback */
595 tevent_req_set_callback(req
, dnsupdate_RODC_callback
, st
);
597 msg
->defer_reply
= true;
603 startup the dns update task
605 static void dnsupdate_task_init(struct task_server
*task
)
608 struct dnsupdate_service
*service
;
610 if (lpcfg_server_role(task
->lp_ctx
) != ROLE_ACTIVE_DIRECTORY_DC
) {
611 /* not useful for non-DC */
615 task_server_set_title(task
, "task[dnsupdate]");
617 service
= talloc_zero(task
, struct dnsupdate_service
);
619 task_server_terminate(task
, "dnsupdate_task_init: out of memory", true);
622 service
->task
= task
;
623 task
->private_data
= service
;
625 service
->system_session_info
= system_session(service
->task
->lp_ctx
);
626 if (!service
->system_session_info
) {
627 task_server_terminate(task
,
628 "dnsupdate: Failed to obtain server credentials\n",
633 service
->samdb
= samdb_connect(service
, service
->task
->event_ctx
, task
->lp_ctx
,
634 service
->system_session_info
, 0);
635 if (!service
->samdb
) {
636 task_server_terminate(task
, "dnsupdate: Failed to connect to local samdb\n",
641 service
->confupdate
.interval
= lpcfg_parm_int(task
->lp_ctx
, NULL
,
642 "dnsupdate", "config interval", 60); /* in seconds */
644 service
->nameupdate
.interval
= lpcfg_parm_int(task
->lp_ctx
, NULL
,
645 "dnsupdate", "name interval", 600); /* in seconds */
647 dnsupdate_rebuild(service
);
648 status
= dnsupdate_confupdate_schedule(service
);
649 if (!NT_STATUS_IS_OK(status
)) {
650 task_server_terminate(task
, talloc_asprintf(task
,
651 "dnsupdate: Failed to confupdate schedule: %s\n",
652 nt_errstr(status
)), true);
656 dnsupdate_check_names(service
);
657 status
= dnsupdate_nameupdate_schedule(service
);
658 if (!NT_STATUS_IS_OK(status
)) {
659 task_server_terminate(task
, talloc_asprintf(task
,
660 "dnsupdate: Failed to nameupdate schedule: %s\n",
661 nt_errstr(status
)), true);
665 irpc_add_name(task
->msg_ctx
, "dnsupdate");
667 IRPC_REGISTER(task
->msg_ctx
, irpc
, DNSUPDATE_RODC
,
668 dnsupdate_dnsupdate_RODC
, service
);
670 /* create the intial file */
671 dnsupdate_rebuild(service
);
676 register ourselves as a available server
678 NTSTATUS
server_service_dnsupdate_init(void)
680 return register_server_service("dnsupdate", dnsupdate_task_init
);