LCOV - code coverage report
Current view: top level - source4/dsdb/kcc - kcc_service.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 114 164 69.5 %
Date: 2024-04-21 15:09:00 Functions: 8 8 100.0 %

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

Generated by: LCOV version 1.14