Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Wrapper for krb5_init_context
4 :
5 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 : Copyright (C) Andrew Tridgell 2005
7 : Copyright (C) Stefan Metzmacher 2004
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/kerberos.h"
25 : #include <tevent.h>
26 : #include "auth/kerberos/kerberos.h"
27 : #include "lib/socket/socket.h"
28 : #include "lib/stream/packet.h"
29 : #include "system/network.h"
30 : #include "param/param.h"
31 : #include "libcli/resolve/resolve.h"
32 : #include "../lib/tsocket/tsocket.h"
33 : #include "krb5_init_context.h"
34 : #ifdef SAMBA4_USES_HEIMDAL
35 : #include "../lib/dbwrap/dbwrap.h"
36 : #include "../lib/dbwrap/dbwrap_rbt.h"
37 : #include "../lib/util/util_tdb.h"
38 : #include <krb5/send_to_kdc_plugin.h>
39 : #endif
40 :
41 : /*
42 : context structure for operations on cldap packets
43 : */
44 : struct smb_krb5_socket {
45 : struct socket_context *sock;
46 :
47 : /* the fd event */
48 : struct tevent_fd *fde;
49 :
50 : NTSTATUS status;
51 : DATA_BLOB request, reply;
52 :
53 : struct packet_context *packet;
54 :
55 : size_t partial_read;
56 : #ifdef SAMBA4_USES_HEIMDAL
57 : krb5_krbhst_info *hi;
58 : #endif
59 : };
60 :
61 470549 : static krb5_error_code smb_krb5_context_destroy(struct smb_krb5_context *ctx)
62 : {
63 : #ifdef SAMBA4_USES_HEIMDAL
64 387330 : if (ctx->pvt_log_data) {
65 : /* Otherwise krb5_free_context will try and close what we
66 : * have already free()ed */
67 387330 : krb5_set_warn_dest(ctx->krb5_context, NULL);
68 387330 : krb5_closelog(ctx->krb5_context,
69 387330 : (krb5_log_facility *)ctx->pvt_log_data);
70 : }
71 : #endif
72 470549 : krb5_free_context(ctx->krb5_context);
73 470549 : return 0;
74 : }
75 :
76 : #ifdef SAMBA4_USES_HEIMDAL
77 : /* We never close down the DEBUG system, and no need to unreference the use */
78 387330 : static void smb_krb5_debug_close(void *private_data) {
79 387330 : return;
80 : }
81 : #endif
82 :
83 : #ifdef SAMBA4_USES_HEIMDAL
84 2129142 : static void smb_krb5_debug_wrapper(
85 : #ifdef HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT
86 : krb5_context ctx,
87 : #endif /* HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT */
88 : const char *timestr, const char *msg, void *private_data)
89 : {
90 2129142 : DEBUGC(DBGC_KERBEROS, 3, ("Kerberos: %s\n", msg));
91 2129142 : }
92 : #endif
93 :
94 : #ifdef SAMBA4_USES_HEIMDAL
95 : /*
96 : handle recv events on a smb_krb5 socket
97 : */
98 21256 : static void smb_krb5_socket_recv(struct smb_krb5_socket *smb_krb5)
99 : {
100 21256 : TALLOC_CTX *tmp_ctx = talloc_new(smb_krb5);
101 1170 : DATA_BLOB blob;
102 1170 : size_t nread, dsize;
103 :
104 21256 : smb_krb5->status = socket_pending(smb_krb5->sock, &dsize);
105 21256 : if (!NT_STATUS_IS_OK(smb_krb5->status)) {
106 0 : talloc_free(tmp_ctx);
107 0 : return;
108 : }
109 :
110 21256 : blob = data_blob_talloc(tmp_ctx, NULL, dsize);
111 21256 : if (blob.data == NULL && dsize != 0) {
112 0 : smb_krb5->status = NT_STATUS_NO_MEMORY;
113 0 : talloc_free(tmp_ctx);
114 0 : return;
115 : }
116 :
117 21256 : smb_krb5->status = socket_recv(smb_krb5->sock, blob.data, blob.length, &nread);
118 21256 : if (!NT_STATUS_IS_OK(smb_krb5->status)) {
119 0 : talloc_free(tmp_ctx);
120 0 : return;
121 : }
122 21256 : blob.length = nread;
123 :
124 21256 : if (nread == 0) {
125 0 : smb_krb5->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
126 0 : talloc_free(tmp_ctx);
127 0 : return;
128 : }
129 :
130 21256 : DEBUG(4,("Received smb_krb5 packet of length %d\n",
131 : (int)blob.length));
132 :
133 21256 : talloc_steal(smb_krb5, blob.data);
134 21256 : smb_krb5->reply = blob;
135 21256 : talloc_free(tmp_ctx);
136 : }
137 :
138 24285 : static NTSTATUS smb_krb5_full_packet(void *private_data, DATA_BLOB data)
139 : {
140 24285 : struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
141 24285 : talloc_steal(smb_krb5, data.data);
142 24285 : smb_krb5->reply = data;
143 24285 : smb_krb5->reply.length -= 4;
144 24285 : smb_krb5->reply.data += 4;
145 24285 : return NT_STATUS_OK;
146 : }
147 :
148 : /*
149 : handle request timeouts
150 : */
151 4 : static void smb_krb5_request_timeout(struct tevent_context *event_ctx,
152 : struct tevent_timer *te, struct timeval t,
153 : void *private_data)
154 : {
155 4 : struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
156 4 : DEBUG(5,("Timed out smb_krb5 packet\n"));
157 4 : smb_krb5->status = NT_STATUS_IO_TIMEOUT;
158 4 : }
159 :
160 0 : static void smb_krb5_error_handler(void *private_data, NTSTATUS status)
161 : {
162 0 : struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
163 0 : smb_krb5->status = status;
164 0 : }
165 :
166 : /*
167 : handle send events on a smb_krb5 socket
168 : */
169 15134269 : static void smb_krb5_socket_send(struct smb_krb5_socket *smb_krb5)
170 : {
171 1170 : NTSTATUS status;
172 :
173 1170 : size_t len;
174 :
175 15134269 : len = smb_krb5->request.length;
176 15134269 : status = socket_send(smb_krb5->sock, &smb_krb5->request, &len);
177 :
178 15134269 : if (!NT_STATUS_IS_OK(status)) return;
179 :
180 21256 : TEVENT_FD_READABLE(smb_krb5->fde);
181 :
182 21256 : TEVENT_FD_NOT_WRITEABLE(smb_krb5->fde);
183 21256 : return;
184 : }
185 :
186 :
187 : /*
188 : handle fd events on a smb_krb5_socket
189 : */
190 15226734 : static void smb_krb5_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
191 : uint16_t flags, void *private_data)
192 : {
193 15226734 : struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
194 15226734 : switch (smb_krb5->hi->proto) {
195 15155525 : case KRB5_KRBHST_UDP:
196 15155525 : if (flags & TEVENT_FD_READ) {
197 21256 : smb_krb5_socket_recv(smb_krb5);
198 21256 : return;
199 : }
200 15134269 : if (flags & TEVENT_FD_WRITE) {
201 15134269 : smb_krb5_socket_send(smb_krb5);
202 15134269 : return;
203 : }
204 : /* not reached */
205 0 : return;
206 71209 : case KRB5_KRBHST_TCP:
207 71209 : if (flags & TEVENT_FD_READ) {
208 46870 : packet_recv(smb_krb5->packet);
209 46870 : return;
210 : }
211 24339 : if (flags & TEVENT_FD_WRITE) {
212 24339 : packet_queue_run(smb_krb5->packet);
213 24339 : return;
214 : }
215 : /* not reached */
216 0 : return;
217 0 : case KRB5_KRBHST_HTTP:
218 : /* can't happen */
219 0 : break;
220 : }
221 : }
222 :
223 45545 : static krb5_error_code smb_krb5_send_and_recv_func_int(struct smb_krb5_context *smb_krb5_context,
224 : struct tevent_context *ev,
225 : krb5_krbhst_info *hi,
226 : struct addrinfo *ai,
227 : smb_krb5_send_to_kdc_func func,
228 : void *data,
229 : time_t timeout,
230 : const krb5_data *send_buf,
231 : krb5_data *recv_buf)
232 : {
233 1755 : krb5_error_code ret;
234 1755 : NTSTATUS status;
235 1755 : const char *name;
236 1755 : struct addrinfo *a;
237 1755 : struct smb_krb5_socket *smb_krb5;
238 :
239 1755 : DATA_BLOB send_blob;
240 :
241 45545 : TALLOC_CTX *frame = talloc_stackframe();
242 45545 : if (frame == NULL) {
243 0 : return ENOMEM;
244 : }
245 :
246 45545 : send_blob = data_blob_const(send_buf->data, send_buf->length);
247 :
248 45549 : for (a = ai; a; a = a->ai_next) {
249 1755 : struct socket_address *remote_addr;
250 45545 : smb_krb5 = talloc(frame, struct smb_krb5_socket);
251 45545 : if (!smb_krb5) {
252 0 : TALLOC_FREE(frame);
253 0 : return ENOMEM;
254 : }
255 45545 : smb_krb5->hi = hi;
256 :
257 45545 : switch (a->ai_family) {
258 43790 : case PF_INET:
259 43790 : name = "ipv4";
260 43790 : break;
261 : #ifdef HAVE_IPV6
262 0 : case PF_INET6:
263 0 : name = "ipv6";
264 0 : break;
265 : #endif
266 0 : default:
267 0 : TALLOC_FREE(frame);
268 0 : return EINVAL;
269 : }
270 :
271 45545 : status = NT_STATUS_INVALID_PARAMETER;
272 45545 : switch (hi->proto) {
273 21260 : case KRB5_KRBHST_UDP:
274 21260 : status = socket_create(smb_krb5, name,
275 : SOCKET_TYPE_DGRAM,
276 : &smb_krb5->sock, 0);
277 21260 : break;
278 24285 : case KRB5_KRBHST_TCP:
279 24285 : status = socket_create(smb_krb5, name,
280 : SOCKET_TYPE_STREAM,
281 : &smb_krb5->sock, 0);
282 24285 : break;
283 0 : case KRB5_KRBHST_HTTP:
284 0 : TALLOC_FREE(frame);
285 0 : return EINVAL;
286 : }
287 45545 : if (!NT_STATUS_IS_OK(status)) {
288 0 : talloc_free(smb_krb5);
289 4 : continue;
290 : }
291 :
292 45545 : remote_addr = socket_address_from_sockaddr(smb_krb5, a->ai_addr, a->ai_addrlen);
293 45545 : if (!remote_addr) {
294 0 : talloc_free(smb_krb5);
295 0 : continue;
296 : }
297 :
298 45545 : status = socket_connect_ev(smb_krb5->sock, NULL, remote_addr, 0, ev);
299 45545 : if (!NT_STATUS_IS_OK(status)) {
300 0 : talloc_free(smb_krb5);
301 0 : continue;
302 : }
303 :
304 : /* Setup the FDE, start listening for read events
305 : * from the start (otherwise we may miss a socket
306 : * drop) and mark as AUTOCLOSE along with the fde */
307 :
308 : /* This is equivalent to EVENT_FD_READABLE(smb_krb5->fde) */
309 45545 : smb_krb5->fde = tevent_add_fd(ev, smb_krb5->sock,
310 : socket_get_fd(smb_krb5->sock),
311 : TEVENT_FD_READ,
312 : smb_krb5_socket_handler, smb_krb5);
313 : /* its now the job of the event layer to close the socket */
314 45545 : tevent_fd_set_close_fn(smb_krb5->fde, socket_tevent_fd_close_fn);
315 45545 : socket_set_flags(smb_krb5->sock, SOCKET_FLAG_NOCLOSE);
316 :
317 45545 : tevent_add_timer(ev, smb_krb5,
318 : timeval_current_ofs(timeout, 0),
319 : smb_krb5_request_timeout, smb_krb5);
320 :
321 45545 : smb_krb5->status = NT_STATUS_OK;
322 45545 : smb_krb5->reply = data_blob(NULL, 0);
323 :
324 45545 : switch (hi->proto) {
325 21260 : case KRB5_KRBHST_UDP:
326 21260 : TEVENT_FD_WRITEABLE(smb_krb5->fde);
327 21260 : smb_krb5->request = send_blob;
328 21260 : break;
329 24285 : case KRB5_KRBHST_TCP:
330 :
331 24285 : smb_krb5->packet = packet_init(smb_krb5);
332 24285 : if (smb_krb5->packet == NULL) {
333 0 : talloc_free(smb_krb5);
334 0 : return ENOMEM;
335 : }
336 24285 : packet_set_private(smb_krb5->packet, smb_krb5);
337 24285 : packet_set_socket(smb_krb5->packet, smb_krb5->sock);
338 24285 : packet_set_callback(smb_krb5->packet, smb_krb5_full_packet);
339 24285 : packet_set_full_request(smb_krb5->packet, packet_full_request_u32);
340 24285 : packet_set_error_handler(smb_krb5->packet, smb_krb5_error_handler);
341 24285 : packet_set_event_context(smb_krb5->packet, ev);
342 24285 : packet_set_fde(smb_krb5->packet, smb_krb5->fde);
343 :
344 24285 : smb_krb5->request = data_blob_talloc(smb_krb5, NULL, send_blob.length + 4);
345 24285 : RSIVAL(smb_krb5->request.data, 0, send_blob.length);
346 24285 : memcpy(smb_krb5->request.data+4, send_blob.data, send_blob.length);
347 24285 : packet_send(smb_krb5->packet, smb_krb5->request);
348 24285 : break;
349 0 : case KRB5_KRBHST_HTTP:
350 0 : TALLOC_FREE(frame);
351 0 : return EINVAL;
352 : }
353 15710969 : while ((NT_STATUS_IS_OK(smb_krb5->status)) && !smb_krb5->reply.length) {
354 15665424 : if (tevent_loop_once(ev) != 0) {
355 0 : TALLOC_FREE(frame);
356 0 : return EINVAL;
357 : }
358 :
359 15665424 : if (func) {
360 : /* After each and every event loop, reset the
361 : * send_to_kdc pointers to what they were when
362 : * we entered this loop. That way, if a
363 : * nested event has invalidated them, we put
364 : * it back before we return to the heimdal
365 : * code */
366 15626963 : ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
367 : NULL, /* send_to_realm */
368 : func,
369 : data);
370 15626963 : if (ret != 0) {
371 0 : TALLOC_FREE(frame);
372 0 : return ret;
373 : }
374 : }
375 : }
376 45545 : if (NT_STATUS_EQUAL(smb_krb5->status, NT_STATUS_IO_TIMEOUT)) {
377 4 : talloc_free(smb_krb5);
378 4 : continue;
379 : }
380 :
381 45541 : if (!NT_STATUS_IS_OK(smb_krb5->status)) {
382 0 : struct tsocket_address *addr = socket_address_to_tsocket_address(smb_krb5, remote_addr);
383 0 : const char *addr_string = NULL;
384 0 : if (addr) {
385 0 : addr_string = tsocket_address_inet_addr_string(addr, smb_krb5);
386 : } else {
387 0 : addr_string = NULL;
388 : }
389 0 : DEBUG(2,("Error reading smb_krb5 reply packet: %s from %s\n", nt_errstr(smb_krb5->status),
390 : addr_string));
391 0 : talloc_free(smb_krb5);
392 0 : continue;
393 : }
394 :
395 45541 : ret = krb5_data_copy(recv_buf, smb_krb5->reply.data, smb_krb5->reply.length);
396 45541 : if (ret) {
397 0 : TALLOC_FREE(frame);
398 0 : return ret;
399 : }
400 45541 : talloc_free(smb_krb5);
401 :
402 45541 : break;
403 : }
404 45545 : TALLOC_FREE(frame);
405 45545 : if (a) {
406 45541 : return 0;
407 : }
408 4 : return KRB5_KDC_UNREACH;
409 : }
410 :
411 31796 : krb5_error_code smb_krb5_send_and_recv_func(struct smb_krb5_context *smb_krb5_context,
412 : void *data,
413 : krb5_krbhst_info *hi,
414 : time_t timeout,
415 : const krb5_data *send_buf,
416 : krb5_data *recv_buf)
417 : {
418 1755 : krb5_error_code ret;
419 1755 : struct addrinfo *ai;
420 :
421 1755 : struct tevent_context *ev;
422 31796 : TALLOC_CTX *frame = talloc_stackframe();
423 31796 : if (frame == NULL) {
424 0 : return ENOMEM;
425 : }
426 :
427 31796 : if (data == NULL) {
428 : /* If no event context was available, then create one for this loop */
429 0 : ev = samba_tevent_context_init(frame);
430 0 : if (ev == NULL) {
431 0 : TALLOC_FREE(frame);
432 0 : return ENOMEM;
433 : }
434 : } else {
435 31796 : ev = talloc_get_type_abort(data, struct tevent_context);
436 : }
437 :
438 31796 : ret = krb5_krbhst_get_addrinfo(smb_krb5_context->krb5_context, hi, &ai);
439 31796 : if (ret) {
440 0 : TALLOC_FREE(frame);
441 0 : return ret;
442 : }
443 :
444 31796 : ret = smb_krb5_send_and_recv_func_int(smb_krb5_context,
445 : ev, hi, ai,
446 : smb_krb5_send_and_recv_func,
447 : data, timeout, send_buf, recv_buf);
448 31796 : TALLOC_FREE(frame);
449 31796 : return ret;
450 : }
451 :
452 13749 : krb5_error_code smb_krb5_send_and_recv_func_forced_tcp(struct smb_krb5_context *smb_krb5_context,
453 : struct addrinfo *ai,
454 : time_t timeout,
455 : const krb5_data *send_buf,
456 : krb5_data *recv_buf)
457 : {
458 0 : krb5_error_code k5ret;
459 13749 : krb5_krbhst_info hi = {
460 : .proto = KRB5_KRBHST_TCP,
461 : };
462 0 : struct tevent_context *ev;
463 13749 : TALLOC_CTX *frame = talloc_stackframe();
464 13749 : if (frame == NULL) {
465 0 : return ENOMEM;
466 : }
467 :
468 : /* no event context is passed in, create one for this loop */
469 13749 : ev = samba_tevent_context_init(frame);
470 13749 : if (ev == NULL) {
471 0 : TALLOC_FREE(frame);
472 0 : return ENOMEM;
473 : }
474 :
475 : /* No need to pass in send_and_recv functions, we won't nest on this private event loop */
476 13749 : k5ret = smb_krb5_send_and_recv_func_int(smb_krb5_context, ev, &hi, ai, NULL, NULL,
477 : timeout, send_buf, recv_buf);
478 13749 : TALLOC_FREE(frame);
479 13749 : return k5ret;
480 : }
481 :
482 : static struct db_context *smb_krb5_plugin_db;
483 :
484 : struct smb_krb5_send_to_kdc_state {
485 : intptr_t key_ptr;
486 : struct smb_krb5_context *smb_krb5_context;
487 : smb_krb5_send_to_realm_func send_to_realm;
488 : smb_krb5_send_to_kdc_func send_to_kdc;
489 : void *private_data;
490 : };
491 :
492 10774 : static int smb_krb5_send_to_kdc_state_destructor(struct smb_krb5_send_to_kdc_state *state)
493 : {
494 10774 : TDB_DATA key = make_tdb_data((uint8_t *)&state->key_ptr, sizeof(state->key_ptr));
495 10774 : struct db_record *rec = NULL;
496 123 : NTSTATUS status;
497 :
498 10774 : rec = dbwrap_fetch_locked(smb_krb5_plugin_db, state, key);
499 10774 : if (rec == NULL) {
500 0 : return 0;
501 : }
502 :
503 10774 : status = dbwrap_record_delete(rec);
504 10774 : TALLOC_FREE(rec);
505 10774 : if (!NT_STATUS_IS_OK(status)) {
506 0 : return -1;
507 : }
508 :
509 10774 : state->smb_krb5_context = NULL;
510 10774 : return 0;
511 : }
512 :
513 15652698 : krb5_error_code smb_krb5_set_send_to_kdc_func(struct smb_krb5_context *smb_krb5_context,
514 : smb_krb5_send_to_realm_func send_to_realm,
515 : smb_krb5_send_to_kdc_func send_to_kdc,
516 : void *private_data)
517 : {
518 15652698 : intptr_t key_ptr = (intptr_t)smb_krb5_context->krb5_context;
519 15652698 : TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
520 15652698 : intptr_t value_ptr = (intptr_t)NULL;
521 15652698 : TDB_DATA value = make_tdb_data(NULL, 0);
522 15652698 : struct db_record *rec = NULL;
523 15652698 : struct smb_krb5_send_to_kdc_state *state = NULL;
524 5296 : NTSTATUS status;
525 :
526 15652698 : rec = dbwrap_fetch_locked(smb_krb5_plugin_db, smb_krb5_context, key);
527 15652698 : if (rec == NULL) {
528 0 : return ENOMEM;
529 : }
530 :
531 15652698 : value = dbwrap_record_get_value(rec);
532 15652698 : if (value.dsize != 0) {
533 15641886 : SMB_ASSERT(value.dsize == sizeof(value_ptr));
534 15641886 : memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
535 15641886 : state = talloc_get_type_abort((const void *)value_ptr,
536 : struct smb_krb5_send_to_kdc_state);
537 15641886 : if (send_to_realm == NULL && send_to_kdc == NULL) {
538 0 : status = dbwrap_record_delete(rec);
539 0 : TALLOC_FREE(rec);
540 0 : if (!NT_STATUS_IS_OK(status)) {
541 0 : return EINVAL;
542 : }
543 0 : return 0;
544 : }
545 15641886 : state->send_to_realm = send_to_realm;
546 15641886 : state->send_to_kdc = send_to_kdc;
547 15641886 : state->private_data = private_data;
548 15641886 : TALLOC_FREE(rec);
549 15641886 : return 0;
550 : }
551 :
552 10812 : if (send_to_kdc == NULL && send_to_realm == NULL) {
553 0 : TALLOC_FREE(rec);
554 0 : return 0;
555 : }
556 :
557 10812 : state = talloc_zero(smb_krb5_context,
558 : struct smb_krb5_send_to_kdc_state);
559 10812 : if (state == NULL) {
560 0 : TALLOC_FREE(rec);
561 0 : return ENOMEM;
562 : }
563 10812 : state->key_ptr = key_ptr;
564 10812 : state->smb_krb5_context = smb_krb5_context;
565 10812 : state->send_to_realm = send_to_realm;
566 10812 : state->send_to_kdc = send_to_kdc;
567 10812 : state->private_data = private_data;
568 :
569 10812 : value_ptr = (intptr_t)state;
570 10812 : value = make_tdb_data((uint8_t *)&value_ptr, sizeof(value_ptr));
571 :
572 10812 : status = dbwrap_record_store(rec, value, TDB_INSERT);
573 10812 : TALLOC_FREE(rec);
574 10812 : if (!NT_STATUS_IS_OK(status)) {
575 0 : return EINVAL;
576 : }
577 10812 : talloc_set_destructor(state, smb_krb5_send_to_kdc_state_destructor);
578 :
579 10812 : return 0;
580 : }
581 :
582 37210 : static krb5_error_code smb_krb5_plugin_init(krb5_context context, void **pctx)
583 : {
584 37210 : *pctx = NULL;
585 37210 : return 0;
586 : }
587 :
588 5058 : static void smb_krb5_plugin_fini(void *ctx)
589 : {
590 5058 : }
591 :
592 68110 : static void smb_krb5_send_to_kdc_state_parser(TDB_DATA key, TDB_DATA value,
593 : void *private_data)
594 : {
595 68110 : struct smb_krb5_send_to_kdc_state **state =
596 : (struct smb_krb5_send_to_kdc_state **)private_data;
597 2925 : intptr_t value_ptr;
598 :
599 68110 : SMB_ASSERT(value.dsize == sizeof(value_ptr));
600 68110 : memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
601 68110 : *state = talloc_get_type_abort((const void *)value_ptr,
602 : struct smb_krb5_send_to_kdc_state);
603 68110 : }
604 :
605 : static struct smb_krb5_send_to_kdc_state *
606 160493 : smb_krb5_send_to_kdc_get_state(krb5_context context)
607 : {
608 160493 : intptr_t key_ptr = (intptr_t)context;
609 160493 : TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
610 160493 : struct smb_krb5_send_to_kdc_state *state = NULL;
611 6241 : NTSTATUS status;
612 :
613 160493 : status = dbwrap_parse_record(smb_krb5_plugin_db, key,
614 : smb_krb5_send_to_kdc_state_parser,
615 : &state);
616 160493 : if (!NT_STATUS_IS_OK(status)) {
617 89067 : return NULL;
618 : }
619 :
620 68110 : return state;
621 : }
622 :
623 72835 : static krb5_error_code smb_krb5_plugin_send_to_kdc(krb5_context context,
624 : void *ctx,
625 : krb5_krbhst_info *ho,
626 : time_t timeout,
627 : const krb5_data *in,
628 : krb5_data *out)
629 : {
630 72835 : struct smb_krb5_send_to_kdc_state *state = NULL;
631 :
632 72835 : state = smb_krb5_send_to_kdc_get_state(context);
633 72835 : if (state == NULL) {
634 39381 : return KRB5_PLUGIN_NO_HANDLE;
635 : }
636 :
637 31796 : if (state->send_to_kdc == NULL) {
638 0 : return KRB5_PLUGIN_NO_HANDLE;
639 : }
640 :
641 31796 : return state->send_to_kdc(state->smb_krb5_context,
642 : state->private_data,
643 : ho, timeout, in, out);
644 : }
645 :
646 87658 : static krb5_error_code smb_krb5_plugin_send_to_realm(krb5_context context,
647 : void *ctx,
648 : krb5_const_realm realm,
649 : time_t timeout,
650 : const krb5_data *in,
651 : krb5_data *out)
652 : {
653 87658 : struct smb_krb5_send_to_kdc_state *state = NULL;
654 :
655 87658 : state = smb_krb5_send_to_kdc_get_state(context);
656 87658 : if (state == NULL) {
657 49686 : return KRB5_PLUGIN_NO_HANDLE;
658 : }
659 :
660 36314 : if (state->send_to_realm == NULL) {
661 20855 : return KRB5_PLUGIN_NO_HANDLE;
662 : }
663 :
664 14289 : return state->send_to_realm(state->smb_krb5_context,
665 : state->private_data,
666 : realm, timeout, in, out);
667 : }
668 :
669 : static krb5plugin_send_to_kdc_ftable smb_krb5_plugin_ftable = {
670 : KRB5_PLUGIN_SEND_TO_KDC_VERSION_2,
671 : smb_krb5_plugin_init,
672 : smb_krb5_plugin_fini,
673 : smb_krb5_plugin_send_to_kdc,
674 : smb_krb5_plugin_send_to_realm
675 : };
676 : #endif
677 :
678 : krb5_error_code
679 473951 : smb_krb5_init_context_basic(TALLOC_CTX *tmp_ctx,
680 : struct loadparm_context *lp_ctx,
681 : krb5_context *_krb5_context)
682 : {
683 13153 : krb5_error_code ret;
684 : #ifdef SAMBA4_USES_HEIMDAL
685 13153 : char **config_files;
686 13153 : const char *config_file, *realm;
687 : #endif
688 13153 : krb5_context krb5_ctx;
689 :
690 473951 : ret = smb_krb5_init_context_common(&krb5_ctx);
691 473951 : if (ret) {
692 0 : return ret;
693 : }
694 :
695 : /* The MIT Kerberos build relies on using the system krb5.conf file.
696 : * If you really want to use another file please set KRB5_CONFIG
697 : * accordingly. */
698 : #ifdef SAMBA4_USES_HEIMDAL
699 390275 : config_file = lpcfg_config_path(tmp_ctx, lp_ctx, "krb5.conf");
700 390275 : if (!config_file) {
701 0 : krb5_free_context(krb5_ctx);
702 0 : return ENOMEM;
703 : }
704 :
705 : /* Use our local krb5.conf file by default */
706 390275 : ret = krb5_prepend_config_files_default(config_file, &config_files);
707 390275 : if (ret) {
708 0 : DEBUG(1,("krb5_prepend_config_files_default failed (%s)\n",
709 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
710 0 : krb5_free_context(krb5_ctx);
711 0 : return ret;
712 : }
713 :
714 390275 : ret = krb5_set_config_files(krb5_ctx, config_files);
715 390275 : krb5_free_config_files(config_files);
716 390275 : if (ret) {
717 0 : DEBUG(1,("krb5_set_config_files failed (%s)\n",
718 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
719 0 : krb5_free_context(krb5_ctx);
720 0 : return ret;
721 : }
722 :
723 : /*
724 : * This is already called in smb_krb5_init_context_common(),
725 : * but krb5_set_config_files() may resets it.
726 : */
727 390275 : krb5_set_dns_canonicalize_hostname(krb5_ctx, false);
728 :
729 390275 : realm = lpcfg_realm(lp_ctx);
730 390275 : if (realm != NULL) {
731 390275 : ret = krb5_set_default_realm(krb5_ctx, realm);
732 390275 : if (ret) {
733 0 : DEBUG(1,("krb5_set_default_realm failed (%s)\n",
734 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
735 0 : krb5_free_context(krb5_ctx);
736 0 : return ret;
737 : }
738 : }
739 :
740 390275 : if (smb_krb5_plugin_db == NULL) {
741 : /*
742 : * while krb5_plugin_register() takes a krb5_context,
743 : * plugins are registered into a global list, so
744 : * we only do that once
745 : *
746 : * We maintain a separate dispatch table for per
747 : * krb5_context state.
748 : */
749 37150 : ret = krb5_plugin_register(krb5_ctx, PLUGIN_TYPE_DATA,
750 : KRB5_PLUGIN_SEND_TO_KDC,
751 : &smb_krb5_plugin_ftable);
752 37150 : if (ret) {
753 0 : DEBUG(1,("krb5_plugin_register(KRB5_PLUGIN_SEND_TO_KDC) failed (%s)\n",
754 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
755 0 : krb5_free_context(krb5_ctx);
756 0 : return ret;
757 : }
758 37150 : smb_krb5_plugin_db = db_open_rbt(NULL);
759 37150 : if (smb_krb5_plugin_db == NULL) {
760 0 : DEBUG(1,("db_open_rbt() failed\n"));
761 0 : krb5_free_context(krb5_ctx);
762 0 : return ENOMEM;
763 : }
764 : }
765 : #endif
766 473951 : *_krb5_context = krb5_ctx;
767 473951 : return 0;
768 : }
769 :
770 473333 : krb5_error_code smb_krb5_init_context(void *parent_ctx,
771 : struct loadparm_context *lp_ctx,
772 : struct smb_krb5_context **smb_krb5_context)
773 : {
774 13153 : krb5_error_code ret;
775 13153 : TALLOC_CTX *tmp_ctx;
776 13153 : krb5_context kctx;
777 : #ifdef SAMBA4_USES_HEIMDAL
778 13153 : krb5_log_facility *logf;
779 : #endif
780 :
781 473333 : tmp_ctx = talloc_new(parent_ctx);
782 473333 : *smb_krb5_context = talloc_zero(tmp_ctx, struct smb_krb5_context);
783 :
784 473333 : if (!*smb_krb5_context || !tmp_ctx) {
785 0 : talloc_free(tmp_ctx);
786 0 : return ENOMEM;
787 : }
788 :
789 473333 : ret = smb_krb5_init_context_basic(tmp_ctx, lp_ctx, &kctx);
790 473333 : if (ret) {
791 0 : DEBUG(1,("smb_krb5_context_init_basic failed (%s)\n",
792 : error_message(ret)));
793 0 : talloc_free(tmp_ctx);
794 0 : return ret;
795 : }
796 473333 : (*smb_krb5_context)->krb5_context = kctx;
797 :
798 473333 : talloc_set_destructor(*smb_krb5_context, smb_krb5_context_destroy);
799 :
800 : #ifdef SAMBA4_USES_HEIMDAL
801 : /* TODO: Should we have a different name here? */
802 389939 : ret = krb5_initlog(kctx, "Samba", &logf);
803 :
804 389939 : if (ret) {
805 0 : DEBUG(1,("krb5_initlog failed (%s)\n",
806 : smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
807 0 : talloc_free(tmp_ctx);
808 0 : return ret;
809 : }
810 389939 : (*smb_krb5_context)->pvt_log_data = logf;
811 :
812 389939 : ret = krb5_addlog_func(kctx, logf, 0 /* min */, -1 /* max */,
813 : smb_krb5_debug_wrapper,
814 : smb_krb5_debug_close, NULL);
815 389939 : if (ret) {
816 0 : DEBUG(1,("krb5_addlog_func failed (%s)\n",
817 : smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
818 0 : talloc_free(tmp_ctx);
819 0 : return ret;
820 : }
821 389939 : krb5_set_warn_dest(kctx, logf);
822 : #endif
823 473333 : talloc_steal(parent_ctx, *smb_krb5_context);
824 473333 : talloc_free(tmp_ctx);
825 :
826 473333 : return 0;
827 : }
828 :
829 : #ifdef SAMBA4_USES_HEIMDAL
830 11443 : krb5_error_code smb_krb5_context_set_event_ctx(struct smb_krb5_context *smb_krb5_context,
831 : struct tevent_context *ev,
832 : struct tevent_context **previous_ev)
833 : {
834 585 : int ret;
835 11443 : if (!ev) {
836 0 : return EINVAL;
837 : }
838 :
839 11443 : *previous_ev = smb_krb5_context->current_ev;
840 :
841 11443 : smb_krb5_context->current_ev = talloc_reference(smb_krb5_context, ev);
842 11443 : if (!smb_krb5_context->current_ev) {
843 0 : return ENOMEM;
844 : }
845 :
846 : /* Set use of our socket lib */
847 11443 : ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
848 : NULL, /* send_to_realm */
849 : smb_krb5_send_and_recv_func,
850 : ev);
851 11443 : if (ret) {
852 0 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
853 0 : DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
854 : smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
855 0 : talloc_free(tmp_ctx);
856 0 : talloc_unlink(smb_krb5_context, smb_krb5_context->current_ev);
857 0 : smb_krb5_context->current_ev = NULL;
858 0 : return ret;
859 : }
860 10858 : return 0;
861 : }
862 :
863 11443 : krb5_error_code smb_krb5_context_remove_event_ctx(struct smb_krb5_context *smb_krb5_context,
864 : struct tevent_context *previous_ev,
865 : struct tevent_context *ev)
866 : {
867 585 : int ret;
868 11443 : talloc_unlink(smb_krb5_context, ev);
869 : /* If there was a mismatch with things happening on a stack, then don't wipe things */
870 11443 : smb_krb5_context->current_ev = previous_ev;
871 : /* Set use of our socket lib */
872 11443 : ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
873 : NULL, /* send_to_realm */
874 : smb_krb5_send_and_recv_func,
875 : previous_ev);
876 11443 : if (ret) {
877 0 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
878 0 : DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
879 : smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
880 0 : talloc_free(tmp_ctx);
881 0 : return ret;
882 : }
883 10858 : return 0;
884 : }
885 : #endif
|