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 476137 : static krb5_error_code smb_krb5_context_destroy(struct smb_krb5_context *ctx)
62 : {
63 : #ifdef SAMBA4_USES_HEIMDAL
64 393185 : if (ctx->pvt_log_data) {
65 : /* Otherwise krb5_free_context will try and close what we
66 : * have already free()ed */
67 393185 : krb5_set_warn_dest(ctx->krb5_context, NULL);
68 393185 : krb5_closelog(ctx->krb5_context,
69 393185 : (krb5_log_facility *)ctx->pvt_log_data);
70 : }
71 : #endif
72 476137 : krb5_free_context(ctx->krb5_context);
73 476137 : 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 393185 : static void smb_krb5_debug_close(void *private_data) {
79 393185 : return;
80 : }
81 : #endif
82 :
83 : #ifdef SAMBA4_USES_HEIMDAL
84 2182483 : 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 2182483 : DEBUGC(DBGC_KERBEROS, 3, ("Kerberos: %s\n", msg));
91 2182483 : }
92 : #endif
93 :
94 : #ifdef SAMBA4_USES_HEIMDAL
95 : /*
96 : handle recv events on a smb_krb5 socket
97 : */
98 21765 : static void smb_krb5_socket_recv(struct smb_krb5_socket *smb_krb5)
99 : {
100 21765 : TALLOC_CTX *tmp_ctx = talloc_new(smb_krb5);
101 1170 : DATA_BLOB blob;
102 1170 : size_t nread, dsize;
103 :
104 21765 : smb_krb5->status = socket_pending(smb_krb5->sock, &dsize);
105 21765 : if (!NT_STATUS_IS_OK(smb_krb5->status)) {
106 0 : talloc_free(tmp_ctx);
107 0 : return;
108 : }
109 :
110 21765 : blob = data_blob_talloc(tmp_ctx, NULL, dsize);
111 21765 : 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 21765 : smb_krb5->status = socket_recv(smb_krb5->sock, blob.data, blob.length, &nread);
118 21765 : if (!NT_STATUS_IS_OK(smb_krb5->status)) {
119 0 : talloc_free(tmp_ctx);
120 0 : return;
121 : }
122 21765 : blob.length = nread;
123 :
124 21765 : 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 21765 : DEBUG(4,("Received smb_krb5 packet of length %d\n",
131 : (int)blob.length));
132 :
133 21765 : talloc_steal(smb_krb5, blob.data);
134 21765 : smb_krb5->reply = blob;
135 21765 : talloc_free(tmp_ctx);
136 : }
137 :
138 26182 : static NTSTATUS smb_krb5_full_packet(void *private_data, DATA_BLOB data)
139 : {
140 26182 : struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
141 26182 : talloc_steal(smb_krb5, data.data);
142 26182 : smb_krb5->reply = data;
143 26182 : smb_krb5->reply.length -= 4;
144 26182 : smb_krb5->reply.data += 4;
145 26182 : 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 16452917 : 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 16452917 : len = smb_krb5->request.length;
176 16452917 : status = socket_send(smb_krb5->sock, &smb_krb5->request, &len);
177 :
178 16452917 : if (!NT_STATUS_IS_OK(status)) return;
179 :
180 21765 : TEVENT_FD_READABLE(smb_krb5->fde);
181 :
182 21765 : TEVENT_FD_NOT_WRITEABLE(smb_krb5->fde);
183 21765 : return;
184 : }
185 :
186 :
187 : /*
188 : handle fd events on a smb_krb5_socket
189 : */
190 16550964 : static void smb_krb5_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
191 : uint16_t flags, void *private_data)
192 : {
193 16550964 : struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
194 16550964 : switch (smb_krb5->hi->proto) {
195 16474682 : case KRB5_KRBHST_UDP:
196 16474682 : if (flags & TEVENT_FD_READ) {
197 21765 : smb_krb5_socket_recv(smb_krb5);
198 21765 : return;
199 : }
200 16452917 : if (flags & TEVENT_FD_WRITE) {
201 16452917 : smb_krb5_socket_send(smb_krb5);
202 16452917 : return;
203 : }
204 : /* not reached */
205 0 : return;
206 76282 : case KRB5_KRBHST_TCP:
207 76282 : if (flags & TEVENT_FD_READ) {
208 50050 : packet_recv(smb_krb5->packet);
209 50050 : return;
210 : }
211 26232 : if (flags & TEVENT_FD_WRITE) {
212 26232 : packet_queue_run(smb_krb5->packet);
213 26232 : 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 47951 : 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 47951 : TALLOC_CTX *frame = talloc_stackframe();
242 47951 : if (frame == NULL) {
243 0 : return ENOMEM;
244 : }
245 :
246 47951 : send_blob = data_blob_const(send_buf->data, send_buf->length);
247 :
248 47955 : for (a = ai; a; a = a->ai_next) {
249 1755 : struct socket_address *remote_addr;
250 47951 : smb_krb5 = talloc(frame, struct smb_krb5_socket);
251 47951 : if (!smb_krb5) {
252 0 : TALLOC_FREE(frame);
253 0 : return ENOMEM;
254 : }
255 47951 : smb_krb5->hi = hi;
256 :
257 47951 : switch (a->ai_family) {
258 46196 : case PF_INET:
259 46196 : name = "ipv4";
260 46196 : 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 47951 : status = NT_STATUS_INVALID_PARAMETER;
272 47951 : switch (hi->proto) {
273 21769 : case KRB5_KRBHST_UDP:
274 21769 : status = socket_create(smb_krb5, name,
275 : SOCKET_TYPE_DGRAM,
276 : &smb_krb5->sock, 0);
277 21769 : break;
278 26182 : case KRB5_KRBHST_TCP:
279 26182 : status = socket_create(smb_krb5, name,
280 : SOCKET_TYPE_STREAM,
281 : &smb_krb5->sock, 0);
282 26182 : break;
283 0 : case KRB5_KRBHST_HTTP:
284 0 : TALLOC_FREE(frame);
285 0 : return EINVAL;
286 : }
287 47951 : if (!NT_STATUS_IS_OK(status)) {
288 0 : talloc_free(smb_krb5);
289 4 : continue;
290 : }
291 :
292 47951 : remote_addr = socket_address_from_sockaddr(smb_krb5, a->ai_addr, a->ai_addrlen);
293 47951 : if (!remote_addr) {
294 0 : talloc_free(smb_krb5);
295 0 : continue;
296 : }
297 :
298 47951 : status = socket_connect_ev(smb_krb5->sock, NULL, remote_addr, 0, ev);
299 47951 : 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 47951 : 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 47951 : tevent_fd_set_close_fn(smb_krb5->fde, socket_tevent_fd_close_fn);
315 47951 : socket_set_flags(smb_krb5->sock, SOCKET_FLAG_NOCLOSE);
316 :
317 47951 : tevent_add_timer(ev, smb_krb5,
318 : timeval_current_ofs(timeout, 0),
319 : smb_krb5_request_timeout, smb_krb5);
320 :
321 47951 : smb_krb5->status = NT_STATUS_OK;
322 47951 : smb_krb5->reply = data_blob(NULL, 0);
323 :
324 47951 : switch (hi->proto) {
325 21769 : case KRB5_KRBHST_UDP:
326 21769 : TEVENT_FD_WRITEABLE(smb_krb5->fde);
327 21769 : smb_krb5->request = send_blob;
328 21769 : break;
329 26182 : case KRB5_KRBHST_TCP:
330 :
331 26182 : smb_krb5->packet = packet_init(smb_krb5);
332 26182 : if (smb_krb5->packet == NULL) {
333 0 : talloc_free(smb_krb5);
334 0 : return ENOMEM;
335 : }
336 26182 : packet_set_private(smb_krb5->packet, smb_krb5);
337 26182 : packet_set_socket(smb_krb5->packet, smb_krb5->sock);
338 26182 : packet_set_callback(smb_krb5->packet, smb_krb5_full_packet);
339 26182 : packet_set_full_request(smb_krb5->packet, packet_full_request_u32);
340 26182 : packet_set_error_handler(smb_krb5->packet, smb_krb5_error_handler);
341 26182 : packet_set_event_context(smb_krb5->packet, ev);
342 26182 : packet_set_fde(smb_krb5->packet, smb_krb5->fde);
343 :
344 26182 : smb_krb5->request = data_blob_talloc(smb_krb5, NULL, send_blob.length + 4);
345 26182 : RSIVAL(smb_krb5->request.data, 0, send_blob.length);
346 26182 : memcpy(smb_krb5->request.data+4, send_blob.data, send_blob.length);
347 26182 : packet_send(smb_krb5->packet, smb_krb5->request);
348 26182 : break;
349 0 : case KRB5_KRBHST_HTTP:
350 0 : TALLOC_FREE(frame);
351 0 : return EINVAL;
352 : }
353 17048827 : while ((NT_STATUS_IS_OK(smb_krb5->status)) && !smb_krb5->reply.length) {
354 17000876 : if (tevent_loop_once(ev) != 0) {
355 0 : TALLOC_FREE(frame);
356 0 : return EINVAL;
357 : }
358 :
359 17000876 : 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 16958163 : ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
367 : NULL, /* send_to_realm */
368 : func,
369 : data);
370 16958163 : if (ret != 0) {
371 0 : TALLOC_FREE(frame);
372 0 : return ret;
373 : }
374 : }
375 : }
376 47951 : if (NT_STATUS_EQUAL(smb_krb5->status, NT_STATUS_IO_TIMEOUT)) {
377 4 : talloc_free(smb_krb5);
378 4 : continue;
379 : }
380 :
381 47947 : 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 47947 : ret = krb5_data_copy(recv_buf, smb_krb5->reply.data, smb_krb5->reply.length);
396 47947 : if (ret) {
397 0 : TALLOC_FREE(frame);
398 0 : return ret;
399 : }
400 47947 : talloc_free(smb_krb5);
401 :
402 47947 : break;
403 : }
404 47951 : TALLOC_FREE(frame);
405 47951 : if (a) {
406 47947 : return 0;
407 : }
408 4 : return KRB5_KDC_UNREACH;
409 : }
410 :
411 32558 : 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 32558 : TALLOC_CTX *frame = talloc_stackframe();
423 32558 : if (frame == NULL) {
424 0 : return ENOMEM;
425 : }
426 :
427 32558 : 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 32558 : ev = talloc_get_type_abort(data, struct tevent_context);
436 : }
437 :
438 32558 : ret = krb5_krbhst_get_addrinfo(smb_krb5_context->krb5_context, hi, &ai);
439 32558 : if (ret) {
440 0 : TALLOC_FREE(frame);
441 0 : return ret;
442 : }
443 :
444 32558 : 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 32558 : TALLOC_FREE(frame);
449 32558 : return ret;
450 : }
451 :
452 15393 : 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 15393 : krb5_krbhst_info hi = {
460 : .proto = KRB5_KRBHST_TCP,
461 : };
462 0 : struct tevent_context *ev;
463 15393 : TALLOC_CTX *frame = talloc_stackframe();
464 15393 : if (frame == NULL) {
465 0 : return ENOMEM;
466 : }
467 :
468 : /* no event context is passed in, create one for this loop */
469 15393 : ev = samba_tevent_context_init(frame);
470 15393 : 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 15393 : k5ret = smb_krb5_send_and_recv_func_int(smb_krb5_context, ev, &hi, ai, NULL, NULL,
477 : timeout, send_buf, recv_buf);
478 15393 : TALLOC_FREE(frame);
479 15393 : 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 11388 : static int smb_krb5_send_to_kdc_state_destructor(struct smb_krb5_send_to_kdc_state *state)
493 : {
494 11388 : TDB_DATA key = make_tdb_data((uint8_t *)&state->key_ptr, sizeof(state->key_ptr));
495 123 : NTSTATUS status;
496 :
497 11388 : status = dbwrap_delete(smb_krb5_plugin_db, key);
498 11388 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
499 0 : status = NT_STATUS_OK;
500 : }
501 11388 : if (!NT_STATUS_IS_OK(status)) {
502 0 : return -1;
503 : }
504 :
505 11388 : state->smb_krb5_context = NULL;
506 11388 : return 0;
507 : }
508 :
509 16985044 : krb5_error_code smb_krb5_set_send_to_kdc_func(struct smb_krb5_context *smb_krb5_context,
510 : smb_krb5_send_to_realm_func send_to_realm,
511 : smb_krb5_send_to_kdc_func send_to_kdc,
512 : void *private_data)
513 : {
514 16985044 : intptr_t key_ptr = (intptr_t)smb_krb5_context->krb5_context;
515 16985044 : TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
516 16985044 : intptr_t value_ptr = (intptr_t)NULL;
517 16985044 : TDB_DATA value = make_tdb_data(NULL, 0);
518 16985044 : struct db_record *rec = NULL;
519 16985044 : struct smb_krb5_send_to_kdc_state *state = NULL;
520 5292 : NTSTATUS status;
521 :
522 16985044 : rec = dbwrap_fetch_locked(smb_krb5_plugin_db, smb_krb5_context, key);
523 16985044 : if (rec == NULL) {
524 0 : return ENOMEM;
525 : }
526 :
527 16985044 : value = dbwrap_record_get_value(rec);
528 16985044 : if (value.dsize != 0) {
529 16973618 : SMB_ASSERT(value.dsize == sizeof(value_ptr));
530 16973618 : memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
531 16973618 : state = talloc_get_type_abort((const void *)value_ptr,
532 : struct smb_krb5_send_to_kdc_state);
533 16973618 : if (send_to_realm == NULL && send_to_kdc == NULL) {
534 0 : status = dbwrap_record_delete(rec);
535 0 : TALLOC_FREE(rec);
536 0 : if (!NT_STATUS_IS_OK(status)) {
537 0 : return EINVAL;
538 : }
539 0 : return 0;
540 : }
541 16973618 : state->send_to_realm = send_to_realm;
542 16973618 : state->send_to_kdc = send_to_kdc;
543 16973618 : state->private_data = private_data;
544 16973618 : TALLOC_FREE(rec);
545 16973618 : return 0;
546 : }
547 :
548 11426 : if (send_to_kdc == NULL && send_to_realm == NULL) {
549 0 : TALLOC_FREE(rec);
550 0 : return 0;
551 : }
552 :
553 11426 : state = talloc_zero(smb_krb5_context,
554 : struct smb_krb5_send_to_kdc_state);
555 11426 : if (state == NULL) {
556 0 : TALLOC_FREE(rec);
557 0 : return ENOMEM;
558 : }
559 11426 : state->key_ptr = key_ptr;
560 11426 : state->smb_krb5_context = smb_krb5_context;
561 11426 : state->send_to_realm = send_to_realm;
562 11426 : state->send_to_kdc = send_to_kdc;
563 11426 : state->private_data = private_data;
564 :
565 11426 : value_ptr = (intptr_t)state;
566 11426 : value = make_tdb_data((uint8_t *)&value_ptr, sizeof(value_ptr));
567 :
568 11426 : status = dbwrap_record_store(rec, value, TDB_INSERT);
569 11426 : TALLOC_FREE(rec);
570 11426 : if (!NT_STATUS_IS_OK(status)) {
571 0 : return EINVAL;
572 : }
573 11426 : talloc_set_destructor(state, smb_krb5_send_to_kdc_state_destructor);
574 :
575 11426 : return 0;
576 : }
577 :
578 37804 : static krb5_error_code smb_krb5_plugin_init(krb5_context context, void **pctx)
579 : {
580 37804 : *pctx = NULL;
581 37804 : return 0;
582 : }
583 :
584 5218 : static void smb_krb5_plugin_fini(void *ctx)
585 : {
586 5218 : }
587 :
588 71843 : static void smb_krb5_send_to_kdc_state_parser(TDB_DATA key, TDB_DATA value,
589 : void *private_data)
590 : {
591 71843 : struct smb_krb5_send_to_kdc_state **state =
592 : (struct smb_krb5_send_to_kdc_state **)private_data;
593 2925 : intptr_t value_ptr;
594 :
595 71843 : SMB_ASSERT(value.dsize == sizeof(value_ptr));
596 71843 : memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
597 71843 : *state = talloc_get_type_abort((const void *)value_ptr,
598 : struct smb_krb5_send_to_kdc_state);
599 71843 : }
600 :
601 : static struct smb_krb5_send_to_kdc_state *
602 164978 : smb_krb5_send_to_kdc_get_state(krb5_context context)
603 : {
604 164978 : intptr_t key_ptr = (intptr_t)context;
605 164978 : TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
606 164978 : struct smb_krb5_send_to_kdc_state *state = NULL;
607 6241 : NTSTATUS status;
608 :
609 164978 : status = dbwrap_parse_record(smb_krb5_plugin_db, key,
610 : smb_krb5_send_to_kdc_state_parser,
611 : &state);
612 164978 : if (!NT_STATUS_IS_OK(status)) {
613 89819 : return NULL;
614 : }
615 :
616 71843 : return state;
617 : }
618 :
619 73814 : static krb5_error_code smb_krb5_plugin_send_to_kdc(krb5_context context,
620 : void *ctx,
621 : krb5_krbhst_info *ho,
622 : time_t timeout,
623 : const krb5_data *in,
624 : krb5_data *out)
625 : {
626 73814 : struct smb_krb5_send_to_kdc_state *state = NULL;
627 :
628 73814 : state = smb_krb5_send_to_kdc_get_state(context);
629 73814 : if (state == NULL) {
630 39598 : return KRB5_PLUGIN_NO_HANDLE;
631 : }
632 :
633 32558 : if (state->send_to_kdc == NULL) {
634 0 : return KRB5_PLUGIN_NO_HANDLE;
635 : }
636 :
637 32558 : return state->send_to_kdc(state->smb_krb5_context,
638 : state->private_data,
639 : ho, timeout, in, out);
640 : }
641 :
642 91164 : static krb5_error_code smb_krb5_plugin_send_to_realm(krb5_context context,
643 : void *ctx,
644 : krb5_const_realm realm,
645 : time_t timeout,
646 : const krb5_data *in,
647 : krb5_data *out)
648 : {
649 91164 : struct smb_krb5_send_to_kdc_state *state = NULL;
650 :
651 91164 : state = smb_krb5_send_to_kdc_get_state(context);
652 91164 : if (state == NULL) {
653 50221 : return KRB5_PLUGIN_NO_HANDLE;
654 : }
655 :
656 39285 : if (state->send_to_realm == NULL) {
657 21642 : return KRB5_PLUGIN_NO_HANDLE;
658 : }
659 :
660 16473 : return state->send_to_realm(state->smb_krb5_context,
661 : state->private_data,
662 : realm, timeout, in, out);
663 : }
664 :
665 : static krb5plugin_send_to_kdc_ftable smb_krb5_plugin_ftable = {
666 : KRB5_PLUGIN_SEND_TO_KDC_VERSION_2,
667 : smb_krb5_plugin_init,
668 : smb_krb5_plugin_fini,
669 : smb_krb5_plugin_send_to_kdc,
670 : smb_krb5_plugin_send_to_realm
671 : };
672 : #endif
673 :
674 : krb5_error_code
675 479465 : smb_krb5_init_context_basic(TALLOC_CTX *tmp_ctx,
676 : struct loadparm_context *lp_ctx,
677 : krb5_context *_krb5_context)
678 : {
679 13153 : krb5_error_code ret;
680 : #ifdef SAMBA4_USES_HEIMDAL
681 13153 : char **config_files;
682 13153 : const char *config_file, *realm;
683 : #endif
684 13153 : krb5_context krb5_ctx;
685 :
686 479465 : ret = smb_krb5_init_context_common(&krb5_ctx);
687 479465 : if (ret) {
688 0 : return ret;
689 : }
690 :
691 : /* The MIT Kerberos build relies on using the system krb5.conf file.
692 : * If you really want to use another file please set KRB5_CONFIG
693 : * accordingly. */
694 : #ifdef SAMBA4_USES_HEIMDAL
695 396091 : config_file = lpcfg_config_path(tmp_ctx, lp_ctx, "krb5.conf");
696 396091 : if (!config_file) {
697 0 : krb5_free_context(krb5_ctx);
698 0 : return ENOMEM;
699 : }
700 :
701 : /* Use our local krb5.conf file by default */
702 396091 : ret = krb5_prepend_config_files_default(config_file, &config_files);
703 396091 : if (ret) {
704 0 : DEBUG(1,("krb5_prepend_config_files_default failed (%s)\n",
705 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
706 0 : krb5_free_context(krb5_ctx);
707 0 : return ret;
708 : }
709 :
710 396091 : ret = krb5_set_config_files(krb5_ctx, config_files);
711 396091 : krb5_free_config_files(config_files);
712 396091 : if (ret) {
713 0 : DEBUG(1,("krb5_set_config_files failed (%s)\n",
714 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
715 0 : krb5_free_context(krb5_ctx);
716 0 : return ret;
717 : }
718 :
719 : /*
720 : * This is already called in smb_krb5_init_context_common(),
721 : * but krb5_set_config_files() may resets it.
722 : */
723 396091 : krb5_set_dns_canonicalize_hostname(krb5_ctx, false);
724 :
725 396091 : realm = lpcfg_realm(lp_ctx);
726 396091 : if (realm != NULL) {
727 396091 : ret = krb5_set_default_realm(krb5_ctx, realm);
728 396091 : if (ret) {
729 0 : DEBUG(1,("krb5_set_default_realm failed (%s)\n",
730 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
731 0 : krb5_free_context(krb5_ctx);
732 0 : return ret;
733 : }
734 : }
735 :
736 396091 : if (smb_krb5_plugin_db == NULL) {
737 : /*
738 : * while krb5_plugin_register() takes a krb5_context,
739 : * plugins are registered into a global list, so
740 : * we only do that once
741 : *
742 : * We maintain a separate dispatch table for per
743 : * krb5_context state.
744 : */
745 37744 : ret = krb5_plugin_register(krb5_ctx, PLUGIN_TYPE_DATA,
746 : KRB5_PLUGIN_SEND_TO_KDC,
747 : &smb_krb5_plugin_ftable);
748 37744 : if (ret) {
749 0 : DEBUG(1,("krb5_plugin_register(KRB5_PLUGIN_SEND_TO_KDC) failed (%s)\n",
750 : smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
751 0 : krb5_free_context(krb5_ctx);
752 0 : return ret;
753 : }
754 37744 : smb_krb5_plugin_db = db_open_rbt(NULL);
755 37744 : if (smb_krb5_plugin_db == NULL) {
756 0 : DEBUG(1,("db_open_rbt() failed\n"));
757 0 : krb5_free_context(krb5_ctx);
758 0 : return ENOMEM;
759 : }
760 : }
761 : #endif
762 479465 : *_krb5_context = krb5_ctx;
763 479465 : return 0;
764 : }
765 :
766 478847 : krb5_error_code smb_krb5_init_context(void *parent_ctx,
767 : struct loadparm_context *lp_ctx,
768 : struct smb_krb5_context **smb_krb5_context)
769 : {
770 13153 : krb5_error_code ret;
771 13153 : TALLOC_CTX *tmp_ctx;
772 13153 : krb5_context kctx;
773 : #ifdef SAMBA4_USES_HEIMDAL
774 13153 : krb5_log_facility *logf;
775 : #endif
776 :
777 478847 : tmp_ctx = talloc_new(parent_ctx);
778 478847 : *smb_krb5_context = talloc_zero(tmp_ctx, struct smb_krb5_context);
779 :
780 478847 : if (!*smb_krb5_context || !tmp_ctx) {
781 0 : talloc_free(tmp_ctx);
782 0 : return ENOMEM;
783 : }
784 :
785 478847 : ret = smb_krb5_init_context_basic(tmp_ctx, lp_ctx, &kctx);
786 478847 : if (ret) {
787 0 : DEBUG(1,("smb_krb5_context_init_basic failed (%s)\n",
788 : error_message(ret)));
789 0 : talloc_free(tmp_ctx);
790 0 : return ret;
791 : }
792 478847 : (*smb_krb5_context)->krb5_context = kctx;
793 :
794 478847 : talloc_set_destructor(*smb_krb5_context, smb_krb5_context_destroy);
795 :
796 : #ifdef SAMBA4_USES_HEIMDAL
797 : /* TODO: Should we have a different name here? */
798 395755 : ret = krb5_initlog(kctx, "Samba", &logf);
799 :
800 395755 : if (ret) {
801 0 : DEBUG(1,("krb5_initlog failed (%s)\n",
802 : smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
803 0 : talloc_free(tmp_ctx);
804 0 : return ret;
805 : }
806 395755 : (*smb_krb5_context)->pvt_log_data = logf;
807 :
808 395755 : ret = krb5_addlog_func(kctx, logf, 0 /* min */, -1 /* max */,
809 : smb_krb5_debug_wrapper,
810 : smb_krb5_debug_close, NULL);
811 395755 : if (ret) {
812 0 : DEBUG(1,("krb5_addlog_func failed (%s)\n",
813 : smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
814 0 : talloc_free(tmp_ctx);
815 0 : return ret;
816 : }
817 395755 : krb5_set_warn_dest(kctx, logf);
818 : #endif
819 478847 : talloc_steal(parent_ctx, *smb_krb5_context);
820 478847 : talloc_free(tmp_ctx);
821 :
822 478847 : return 0;
823 : }
824 :
825 : #ifdef SAMBA4_USES_HEIMDAL
826 11974 : krb5_error_code smb_krb5_context_set_event_ctx(struct smb_krb5_context *smb_krb5_context,
827 : struct tevent_context *ev,
828 : struct tevent_context **previous_ev)
829 : {
830 585 : int ret;
831 11974 : if (!ev) {
832 0 : return EINVAL;
833 : }
834 :
835 11974 : *previous_ev = smb_krb5_context->current_ev;
836 :
837 11974 : smb_krb5_context->current_ev = talloc_reference(smb_krb5_context, ev);
838 11974 : if (!smb_krb5_context->current_ev) {
839 0 : return ENOMEM;
840 : }
841 :
842 : /* Set use of our socket lib */
843 11974 : ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
844 : NULL, /* send_to_realm */
845 : smb_krb5_send_and_recv_func,
846 : ev);
847 11974 : if (ret) {
848 0 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
849 0 : DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
850 : smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
851 0 : talloc_free(tmp_ctx);
852 0 : talloc_unlink(smb_krb5_context, smb_krb5_context->current_ev);
853 0 : smb_krb5_context->current_ev = NULL;
854 0 : return ret;
855 : }
856 11389 : return 0;
857 : }
858 :
859 11974 : krb5_error_code smb_krb5_context_remove_event_ctx(struct smb_krb5_context *smb_krb5_context,
860 : struct tevent_context *previous_ev,
861 : struct tevent_context *ev)
862 : {
863 585 : int ret;
864 11974 : talloc_unlink(smb_krb5_context, ev);
865 : /* If there was a mismatch with things happening on a stack, then don't wipe things */
866 11974 : smb_krb5_context->current_ev = previous_ev;
867 : /* Set use of our socket lib */
868 11974 : ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
869 : NULL, /* send_to_realm */
870 : smb_krb5_send_and_recv_func,
871 : previous_ev);
872 11974 : if (ret) {
873 0 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
874 0 : DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
875 : smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
876 0 : talloc_free(tmp_ctx);
877 0 : return ret;
878 : }
879 11389 : return 0;
880 : }
881 : #endif
|