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

Generated by: LCOV version 1.14