LCOV - code coverage report
Current view: top level - source4/kdc - kdc-service-mit.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 94 144 65.3 %
Date: 2024-06-13 04:01:37 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Start MIT krb5kdc server within Samba AD
       5             : 
       6             :    Copyright (c) 2014-2016 Andreas Schneider <asn@samba.org>
       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             : #include "includes.h"
      23             : #include "talloc.h"
      24             : #include "tevent.h"
      25             : #include "system/filesys.h"
      26             : #include "lib/param/param.h"
      27             : #include "lib/util/samba_util.h"
      28             : #include "source4/samba/service.h"
      29             : #include "source4/samba/process_model.h"
      30             : #include "kdc/kdc-service-mit.h"
      31             : #include "dynconfig.h"
      32             : #include "libds/common/roles.h"
      33             : #include "lib/socket/netif.h"
      34             : #include "samba/session.h"
      35             : #include "dsdb/samdb/samdb.h"
      36             : #include "kdc/samba_kdc.h"
      37             : #include "kdc/kdc-server.h"
      38             : #include "kdc/kpasswd-service.h"
      39             : #include <kadm5/admin.h>
      40             : #include <kdb.h>
      41             : 
      42             : #include "source4/kdc/mit_kdc_irpc.h"
      43             : 
      44             : /* PROTOTYPES */
      45             : static void mitkdc_server_done(struct tevent_req *subreq);
      46             : 
      47          12 : static int kdc_server_destroy(struct kdc_server *kdc)
      48             : {
      49          12 :         if (kdc->private_data != NULL) {
      50          12 :                 kadm5_destroy(kdc->private_data);
      51             :         }
      52             : 
      53          12 :         return 0;
      54             : }
      55             : 
      56          12 : static NTSTATUS startup_kpasswd_server(TALLOC_CTX *mem_ctx,
      57             :                                        struct kdc_server *kdc,
      58             :                                        struct loadparm_context *lp_ctx,
      59             :                                        struct interface *ifaces)
      60             : {
      61             :         int num_interfaces;
      62             :         int i;
      63             :         TALLOC_CTX *tmp_ctx;
      64          12 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
      65             :         uint16_t kpasswd_port;
      66          12 :         bool done_wildcard = false;
      67             :         bool ok;
      68             : 
      69          12 :         kpasswd_port = lpcfg_kpasswd_port(lp_ctx);
      70          12 :         if (kpasswd_port == 0) {
      71           0 :                 return NT_STATUS_OK;
      72             :         }
      73             : 
      74          12 :         tmp_ctx = talloc_named_const(mem_ctx, 0, "kpasswd");
      75          12 :         if (tmp_ctx == NULL) {
      76           0 :                 return NT_STATUS_NO_MEMORY;
      77             :         }
      78             : 
      79          12 :         num_interfaces = iface_list_count(ifaces);
      80             : 
      81          12 :         ok = lpcfg_bind_interfaces_only(lp_ctx);
      82          12 :         if (!ok) {
      83          12 :                 int num_binds = 0;
      84             :                 char **wcard;
      85             : 
      86          12 :                 wcard = iface_list_wildcard(tmp_ctx);
      87          12 :                 if (wcard == NULL) {
      88           0 :                         status = NT_STATUS_NO_MEMORY;
      89           0 :                         goto out;
      90             :                 }
      91             : 
      92          36 :                 for (i = 0; wcard[i] != NULL; i++) {
      93          24 :                         status = kdc_add_socket(kdc,
      94          24 :                                                 kdc->task->model_ops,
      95             :                                                 "kpasswd",
      96          24 :                                                 wcard[i],
      97             :                                                 kpasswd_port,
      98             :                                                 kpasswd_process,
      99             :                                                 false);
     100          24 :                         if (NT_STATUS_IS_OK(status)) {
     101          24 :                                 num_binds++;
     102             :                         }
     103             :                 }
     104          12 :                 talloc_free(wcard);
     105             : 
     106          12 :                 if (num_binds == 0) {
     107           0 :                         status = NT_STATUS_INVALID_PARAMETER_MIX;
     108           0 :                         goto out;
     109             :                 }
     110             : 
     111          12 :                 done_wildcard = true;
     112             :         }
     113             : 
     114          12 :         for (i = 0; i < num_interfaces; i++) {
     115          12 :                 const char *address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
     116             : 
     117          12 :                 status = kdc_add_socket(kdc,
     118          12 :                                         kdc->task->model_ops,
     119             :                                         "kpasswd",
     120             :                                         address,
     121             :                                         kpasswd_port,
     122             :                                         kpasswd_process,
     123             :                                         done_wildcard);
     124          12 :                 if (NT_STATUS_IS_OK(status)) {
     125          12 :                         goto out;
     126             :                 }
     127             :         }
     128             : 
     129           0 : out:
     130          12 :         talloc_free(tmp_ctx);
     131          12 :         return status;
     132             : }
     133             : 
     134             : /*
     135             :  * Startup a copy of the krb5kdc as a child daemon
     136             :  */
     137          15 : NTSTATUS mitkdc_task_init(struct task_server *task)
     138             : {
     139             :         struct tevent_req *subreq;
     140             :         const char * const *kdc_cmd;
     141             :         struct interface *ifaces;
     142          15 :         char *kdc_config = NULL;
     143             :         struct kdc_server *kdc;
     144             :         krb5_error_code code;
     145             :         NTSTATUS status;
     146             :         kadm5_ret_t ret;
     147             :         kadm5_config_params config;
     148             :         void *server_handle;
     149          15 :         int dbglvl = 0;
     150             : 
     151          15 :         task_server_set_title(task, "task[mitkdc_parent]");
     152             : 
     153          15 :         switch (lpcfg_server_role(task->lp_ctx)) {
     154           0 :         case ROLE_STANDALONE:
     155           0 :                 task_server_terminate(task,
     156             :                                       "The KDC is not required in standalone "
     157             :                                       "server configuration, terminate!",
     158             :                                       false);
     159           0 :                 return NT_STATUS_INVALID_DOMAIN_ROLE;
     160           3 :         case ROLE_DOMAIN_MEMBER:
     161           3 :                 task_server_terminate(task,
     162             :                                       "The KDC is not required in member "
     163             :                                       "server configuration",
     164             :                                       false);
     165           0 :                 return NT_STATUS_INVALID_DOMAIN_ROLE;
     166          12 :         case ROLE_ACTIVE_DIRECTORY_DC:
     167             :                 /* Yes, we want to start the KDC */
     168          12 :                 break;
     169             :         }
     170             : 
     171             :         /* Load interfaces for kpasswd */
     172          12 :         load_interface_list(task, task->lp_ctx, &ifaces);
     173          12 :         if (iface_list_count(ifaces) == 0) {
     174           0 :                 task_server_terminate(task,
     175             :                                       "KDC: no network interfaces configured",
     176             :                                       false);
     177           0 :                 return NT_STATUS_UNSUCCESSFUL;
     178             :         }
     179             : 
     180          12 :         kdc_config = talloc_asprintf(task,
     181             :                                      "%s/kdc.conf",
     182             :                                      lpcfg_private_dir(task->lp_ctx));
     183          12 :         if (kdc_config == NULL) {
     184           0 :                 task_server_terminate(task,
     185             :                                       "KDC: no memory",
     186             :                                       false);
     187           0 :                 return NT_STATUS_NO_MEMORY;
     188             :         }
     189          12 :         setenv("KRB5_KDC_PROFILE", kdc_config, 0);
     190          12 :         TALLOC_FREE(kdc_config);
     191             : 
     192          12 :         dbglvl = debuglevel_get_class(DBGC_KERBEROS);
     193          12 :         if (dbglvl >= 10) {
     194           0 :                 char *kdc_trace_file = talloc_asprintf(task,
     195             :                                                        "%s/mit_kdc_trace.log",
     196             :                                                        get_dyn_LOGFILEBASE());
     197           0 :                 if (kdc_trace_file == NULL) {
     198           0 :                         task_server_terminate(task,
     199             :                                         "KDC: no memory",
     200             :                                         false);
     201           0 :                         return NT_STATUS_NO_MEMORY;
     202             :                 }
     203             : 
     204           0 :                 setenv("KRB5_TRACE", kdc_trace_file, 1);
     205             :         }
     206             : 
     207             :         /* start it as a child process */
     208          12 :         kdc_cmd = lpcfg_mit_kdc_command(task->lp_ctx);
     209             : 
     210          12 :         subreq = samba_runcmd_send(task,
     211             :                                    task->event_ctx,
     212             :                                    timeval_zero(),
     213             :                                    1, /* stdout log level */
     214             :                                    0, /* stderr log level */
     215             :                                    kdc_cmd,
     216             :                                    "-n", /* Don't go into background */
     217             : #if 0
     218             :                                    "-w 2", /* Start two workers */
     219             : #endif
     220             :                                    NULL);
     221          12 :         if (subreq == NULL) {
     222           0 :                 DEBUG(0, ("Failed to start MIT KDC as child daemon\n"));
     223             : 
     224           0 :                 task_server_terminate(task,
     225             :                                       "Failed to startup mitkdc task",
     226             :                                       true);
     227           0 :                 return NT_STATUS_INTERNAL_ERROR;
     228             :         }
     229             : 
     230          12 :         tevent_req_set_callback(subreq, mitkdc_server_done, task);
     231             : 
     232          12 :         DEBUG(5,("Started krb5kdc process\n"));
     233             : 
     234          12 :         status = samba_setup_mit_kdc_irpc(task);
     235          12 :         if (!NT_STATUS_IS_OK(status)) {
     236           0 :                 task_server_terminate(task,
     237             :                                       "Failed to setup kdc irpc service",
     238             :                                       true);
     239             :         }
     240             : 
     241          12 :         DEBUG(5,("Started irpc service for kdc_server\n"));
     242             : 
     243          12 :         kdc = talloc_zero(task, struct kdc_server);
     244          12 :         if (kdc == NULL) {
     245           0 :                 task_server_terminate(task, "KDC: Out of memory", true);
     246           0 :                 return NT_STATUS_NO_MEMORY;
     247             :         }
     248          12 :         talloc_set_destructor(kdc, kdc_server_destroy);
     249             : 
     250          12 :         kdc->task = task;
     251             : 
     252          12 :         kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context);
     253          12 :         if (kdc->base_ctx == NULL) {
     254           0 :                 task_server_terminate(task, "KDC: Out of memory", true);
     255           0 :                 return NT_STATUS_NO_MEMORY;
     256             :         }
     257             : 
     258          12 :         kdc->base_ctx->ev_ctx = task->event_ctx;
     259          12 :         kdc->base_ctx->lp_ctx = task->lp_ctx;
     260             : 
     261          12 :         initialize_krb5_error_table();
     262             : 
     263          12 :         code = smb_krb5_init_context(kdc,
     264          12 :                                      kdc->task->lp_ctx,
     265             :                                      &kdc->smb_krb5_context);
     266          12 :         if (code != 0) {
     267           0 :                 task_server_terminate(task,
     268             :                                       "KDC: Unable to initialize krb5 context",
     269             :                                       true);
     270           0 :                 return NT_STATUS_INTERNAL_ERROR;
     271             :         }
     272             : 
     273          12 :         code = kadm5_init_krb5_context(&kdc->smb_krb5_context->krb5_context);
     274          12 :         if (code != 0) {
     275           0 :                 task_server_terminate(task,
     276             :                                       "KDC: Unable to init kadm5 krb5_context",
     277             :                                       true);
     278           0 :                 return NT_STATUS_INTERNAL_ERROR;
     279             :         }
     280             : 
     281          12 :         ZERO_STRUCT(config);
     282          12 :         config.mask = KADM5_CONFIG_REALM;
     283          12 :         config.realm = discard_const_p(char, lpcfg_realm(kdc->task->lp_ctx));
     284             : 
     285          12 :         ret = kadm5_init(kdc->smb_krb5_context->krb5_context,
     286             :                          discard_const_p(char, "kpasswd"),
     287             :                          NULL, /* pass */
     288             :                          discard_const_p(char, "kpasswd"),
     289             :                          &config,
     290             :                          KADM5_STRUCT_VERSION,
     291             :                          KADM5_API_VERSION_4,
     292             :                          NULL,
     293             :                          &server_handle);
     294          12 :         if (ret != 0) {
     295           0 :                 task_server_terminate(task,
     296             :                                       "KDC: Initialize kadm5",
     297             :                                       true);
     298           0 :                 return NT_STATUS_INTERNAL_ERROR;
     299             :         }
     300          12 :         kdc->private_data = server_handle;
     301             : 
     302          12 :         code = krb5_db_register_keytab(kdc->smb_krb5_context->krb5_context);
     303          12 :         if (code != 0) {
     304           0 :                 task_server_terminate(task,
     305             :                                       "KDC: Unable to KDB",
     306             :                                       true);
     307           0 :                 return NT_STATUS_INTERNAL_ERROR;
     308             :         }
     309             : 
     310          12 :         kdc->kpasswd_keytab_name = talloc_asprintf(kdc, "KDB:");
     311          12 :         if (kdc->kpasswd_keytab_name == NULL) {
     312           0 :                 task_server_terminate(task,
     313             :                                       "KDC: Out of memory",
     314             :                                       true);
     315           0 :                 return NT_STATUS_NO_MEMORY;
     316             :         }
     317             : 
     318          36 :         kdc->samdb = samdb_connect(kdc,
     319          12 :                                    kdc->task->event_ctx,
     320          12 :                                    kdc->task->lp_ctx,
     321          12 :                                    system_session(kdc->task->lp_ctx),
     322             :                                    NULL,
     323             :                                    0);
     324          12 :         if (kdc->samdb == NULL) {
     325           0 :                 task_server_terminate(task,
     326             :                                       "KDC: Unable to connect to samdb",
     327             :                                       true);
     328           0 :                 return NT_STATUS_CONNECTION_INVALID;
     329             :         }
     330             : 
     331          12 :         status = startup_kpasswd_server(kdc,
     332             :                                     kdc,
     333             :                                     task->lp_ctx,
     334             :                                     ifaces);
     335          12 :         if (!NT_STATUS_IS_OK(status)) {
     336           0 :                 task_server_terminate(task,
     337             :                                       "KDC: Unable to start kpasswd server",
     338             :                                       true);
     339           0 :                 return status;
     340             :         }
     341             : 
     342          12 :         DEBUG(5,("Started kpasswd service for kdc_server\n"));
     343             : 
     344          12 :         return NT_STATUS_OK;
     345             : }
     346             : 
     347             : /*
     348             :  * This gets called the kdc exits.
     349             :  */
     350           0 : static void mitkdc_server_done(struct tevent_req *subreq)
     351             : {
     352             :         struct task_server *task =
     353           0 :                 tevent_req_callback_data(subreq,
     354             :                 struct task_server);
     355             :         int sys_errno;
     356             :         int ret;
     357             : 
     358           0 :         ret = samba_runcmd_recv(subreq, &sys_errno);
     359           0 :         if (ret != 0) {
     360           0 :                 DEBUG(0, ("The MIT KDC daemon died with exit status %d\n",
     361             :                           sys_errno));
     362             :         } else {
     363           0 :                 DEBUG(0,("The MIT KDC daemon exited normally\n"));
     364             :         }
     365             : 
     366           0 :         task_server_terminate(task, "mitkdc child process exited", true);
     367           0 : }
     368             : 
     369             : /* Called at MIT KRB5 startup - register ourselves as a server service */
     370             : NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx);
     371             : 
     372          15 : NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx)
     373             : {
     374             :         static const struct service_details details = {
     375             :                 .inhibit_fork_on_accept = true,
     376             :                 /*
     377             :                  * Need to prevent pre-forking on kdc.
     378             :                  * The task_init function is run on the master process only
     379             :                  * and the irpc process name is registered in it's event loop.
     380             :                  * The child worker processes initialise their event loops on
     381             :                  * fork, so are not listening for the irpc event.
     382             :                  *
     383             :                  * The master process does not wait on that event context
     384             :                  * the master process is responsible for managing the worker
     385             :                  * processes not performing work.
     386             :                  */
     387             :                 .inhibit_pre_fork = true,
     388             :                 .task_init = mitkdc_task_init,
     389             :                 .post_fork = NULL
     390             :         };
     391          15 :         return register_server_service(mem_ctx, "kdc", &details);
     392             : }

Generated by: LCOV version 1.13