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