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