LCOV - code coverage report
Current view: top level - source4/dsdb/dns - dns_update.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 142 201 70.6 %
Date: 2024-04-21 15:09:00 Functions: 10 10 100.0 %

          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             : }

Generated by: LCOV version 1.14