2 Unix SMB/CIFS implementation.
4 Start MIT krb5kdc server within Samba AD
6 Copyright (c) 2014-2016 Andreas Schneider <asn@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
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>
42 #include "source4/kdc/mit_kdc_irpc.h"
45 #define DBGC_CLASS DBGC_KERBEROS
48 static void mitkdc_server_done(struct tevent_req
*subreq
);
50 static int kdc_server_destroy(struct kdc_server
*kdc
)
52 if (kdc
->private_data
!= NULL
) {
53 kadm5_destroy(kdc
->private_data
);
59 static NTSTATUS
startup_kpasswd_server(TALLOC_CTX
*mem_ctx
,
60 struct kdc_server
*kdc
,
61 struct loadparm_context
*lp_ctx
,
62 struct interface
*ifaces
)
67 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
68 uint16_t kpasswd_port
;
69 bool done_wildcard
= false;
72 kpasswd_port
= lpcfg_kpasswd_port(lp_ctx
);
73 if (kpasswd_port
== 0) {
77 tmp_ctx
= talloc_named_const(mem_ctx
, 0, "kpasswd");
78 if (tmp_ctx
== NULL
) {
79 return NT_STATUS_NO_MEMORY
;
82 num_interfaces
= iface_list_count(ifaces
);
84 ok
= lpcfg_bind_interfaces_only(lp_ctx
);
89 wcard
= iface_list_wildcard(tmp_ctx
);
91 status
= NT_STATUS_NO_MEMORY
;
95 for (i
= 0; wcard
[i
] != NULL
; i
++) {
96 status
= kdc_add_socket(kdc
,
103 if (NT_STATUS_IS_OK(status
)) {
109 if (num_binds
== 0) {
110 status
= NT_STATUS_INVALID_PARAMETER_MIX
;
114 done_wildcard
= true;
117 for (i
= 0; i
< num_interfaces
; i
++) {
118 const char *address
= talloc_strdup(tmp_ctx
, iface_list_n_ip(ifaces
, i
));
120 status
= kdc_add_socket(kdc
,
121 kdc
->task
->model_ops
,
127 if (NT_STATUS_IS_OK(status
)) {
133 talloc_free(tmp_ctx
);
138 * Startup a copy of the krb5kdc as a child daemon
140 NTSTATUS
mitkdc_task_init(struct task_server
*task
)
142 struct tevent_req
*subreq
;
143 const char * const *kdc_cmd
;
144 struct interface
*ifaces
;
145 char *kdc_config
= NULL
;
146 struct kdc_server
*kdc
;
147 krb5_error_code code
;
150 kadm5_config_params config
;
154 task_server_set_title(task
, "task[mitkdc_parent]");
156 switch (lpcfg_server_role(task
->lp_ctx
)) {
157 case ROLE_STANDALONE
:
158 task_server_terminate(task
,
159 "The KDC is not required in standalone "
160 "server configuration, terminate!",
162 return NT_STATUS_INVALID_DOMAIN_ROLE
;
163 case ROLE_DOMAIN_MEMBER
:
164 task_server_terminate(task
,
165 "The KDC is not required in member "
166 "server configuration",
168 return NT_STATUS_INVALID_DOMAIN_ROLE
;
169 case ROLE_ACTIVE_DIRECTORY_DC
:
170 /* Yes, we want to start the KDC */
174 /* Load interfaces for kpasswd */
175 load_interface_list(task
, task
->lp_ctx
, &ifaces
);
176 if (iface_list_count(ifaces
) == 0) {
177 task_server_terminate(task
,
178 "KDC: no network interfaces configured",
180 return NT_STATUS_UNSUCCESSFUL
;
183 kdc_config
= talloc_asprintf(task
,
185 lpcfg_private_dir(task
->lp_ctx
));
186 if (kdc_config
== NULL
) {
187 task_server_terminate(task
,
190 return NT_STATUS_NO_MEMORY
;
192 setenv("KRB5_KDC_PROFILE", kdc_config
, 0);
193 TALLOC_FREE(kdc_config
);
195 dbglvl
= debuglevel_get_class(DBGC_KERBEROS
);
197 char *kdc_trace_file
= talloc_asprintf(task
,
198 "%s/mit_kdc_trace.log",
199 get_dyn_LOGFILEBASE());
200 if (kdc_trace_file
== NULL
) {
201 task_server_terminate(task
,
204 return NT_STATUS_NO_MEMORY
;
207 setenv("KRB5_TRACE", kdc_trace_file
, 1);
210 /* start it as a child process */
211 kdc_cmd
= lpcfg_mit_kdc_command(task
->lp_ctx
);
213 subreq
= samba_runcmd_send(task
,
216 1, /* stdout log level */
217 0, /* stderr log level */
219 "-n", /* Don't go into background */
221 "-w 2", /* Start two workers */
224 if (subreq
== NULL
) {
225 DBG_ERR("Failed to start MIT KDC as child daemon\n");
227 task_server_terminate(task
,
228 "Failed to startup mitkdc task",
230 return NT_STATUS_INTERNAL_ERROR
;
233 tevent_req_set_callback(subreq
, mitkdc_server_done
, task
);
235 DBG_INFO("Started krb5kdc process\n");
237 status
= samba_setup_mit_kdc_irpc(task
);
238 if (!NT_STATUS_IS_OK(status
)) {
239 task_server_terminate(task
,
240 "Failed to setup kdc irpc service",
244 DBG_INFO("Started irpc service for kdc_server\n");
246 kdc
= talloc_zero(task
, struct kdc_server
);
248 task_server_terminate(task
, "KDC: Out of memory", true);
249 return NT_STATUS_NO_MEMORY
;
251 talloc_set_destructor(kdc
, kdc_server_destroy
);
255 kdc
->base_ctx
= talloc_zero(kdc
, struct samba_kdc_base_context
);
256 if (kdc
->base_ctx
== NULL
) {
257 task_server_terminate(task
, "KDC: Out of memory", true);
258 return NT_STATUS_NO_MEMORY
;
261 kdc
->base_ctx
->ev_ctx
= task
->event_ctx
;
262 kdc
->base_ctx
->lp_ctx
= task
->lp_ctx
;
264 initialize_krb5_error_table();
266 code
= smb_krb5_init_context(kdc
,
268 &kdc
->smb_krb5_context
);
270 task_server_terminate(task
,
271 "KDC: Unable to initialize krb5 context",
273 return NT_STATUS_INTERNAL_ERROR
;
276 code
= kadm5_init_krb5_context(&kdc
->smb_krb5_context
->krb5_context
);
278 task_server_terminate(task
,
279 "KDC: Unable to init kadm5 krb5_context",
281 return NT_STATUS_INTERNAL_ERROR
;
285 config
.mask
= KADM5_CONFIG_REALM
;
286 config
.realm
= discard_const_p(char, lpcfg_realm(kdc
->task
->lp_ctx
));
288 ret
= kadm5_init(kdc
->smb_krb5_context
->krb5_context
,
289 discard_const_p(char, "kpasswd"),
291 discard_const_p(char, "kpasswd"),
293 KADM5_STRUCT_VERSION
,
298 task_server_terminate(task
,
299 "KDC: Initialize kadm5",
301 return NT_STATUS_INTERNAL_ERROR
;
303 kdc
->private_data
= server_handle
;
305 code
= krb5_db_register_keytab(kdc
->smb_krb5_context
->krb5_context
);
307 task_server_terminate(task
,
308 "KDC: Unable to KDB",
310 return NT_STATUS_INTERNAL_ERROR
;
313 kdc
->kpasswd_keytab_name
= talloc_asprintf(kdc
, "KDB:");
314 if (kdc
->kpasswd_keytab_name
== NULL
) {
315 task_server_terminate(task
,
316 "KDC: Out of memory",
318 return NT_STATUS_NO_MEMORY
;
321 status
= startup_kpasswd_server(kdc
,
325 if (!NT_STATUS_IS_OK(status
)) {
326 task_server_terminate(task
,
327 "KDC: Unable to start kpasswd server",
332 DBG_INFO("Started kpasswd service for kdc_server\n");
338 * This gets called the kdc exits.
340 static void mitkdc_server_done(struct tevent_req
*subreq
)
342 struct task_server
*task
=
343 tevent_req_callback_data(subreq
,
348 ret
= samba_runcmd_recv(subreq
, &sys_errno
);
350 DBG_ERR("The MIT KDC daemon died with exit status %d\n",
353 DBG_ERR("The MIT KDC daemon exited normally\n");
356 task_server_terminate(task
, "mitkdc child process exited", true);
359 /* Called at MIT KRB5 startup - register ourselves as a server service */
360 NTSTATUS
server_service_mitkdc_init(TALLOC_CTX
*mem_ctx
);
362 NTSTATUS
server_service_mitkdc_init(TALLOC_CTX
*mem_ctx
)
364 static const struct service_details details
= {
365 .inhibit_fork_on_accept
= true,
367 * Need to prevent pre-forking on kdc.
368 * The task_init function is run on the master process only
369 * and the irpc process name is registered in it's event loop.
370 * The child worker processes initialise their event loops on
371 * fork, so are not listening for the irpc event.
373 * The master process does not wait on that event context
374 * the master process is responsible for managing the worker
375 * processes not performing work.
377 .inhibit_pre_fork
= true,
378 .task_init
= mitkdc_task_init
,
381 return register_server_service(mem_ctx
, "kdc", &details
);