Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : KDC related functions
5 :
6 : Copyright (c) 2005-2008 Andrew Bartlett <abartlet@samba.org>
7 : Copyright (c) 2005 Andrew Tridgell <tridge@samba.org>
8 : Copyright (c) 2005 Stefan Metzmacher <metze@samba.org>
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "param/param.h"
26 : #include "samba/process_model.h"
27 : #include "lib/tsocket/tsocket.h"
28 : #include "libcli/util/tstream.h"
29 : #include "kdc/kdc-server.h"
30 : #include "kdc/kdc-proxy.h"
31 : #include "lib/stream/packet.h"
32 :
33 : /*
34 : * State of an open tcp connection
35 : */
36 : struct kdc_tcp_connection {
37 : /* stream connection we belong to */
38 : struct stream_connection *conn;
39 :
40 : /* the kdc_server the connection belongs to */
41 : struct kdc_socket *kdc_socket;
42 :
43 : struct tstream_context *tstream;
44 :
45 : struct tevent_queue *send_queue;
46 : };
47 :
48 : struct kdc_tcp_call {
49 : struct kdc_tcp_connection *kdc_conn;
50 : DATA_BLOB in;
51 : DATA_BLOB out;
52 : uint8_t out_hdr[4];
53 : struct iovec out_iov[2];
54 : };
55 :
56 : struct kdc_udp_call {
57 : struct kdc_udp_socket *sock;
58 : struct tsocket_address *src;
59 : DATA_BLOB in;
60 : DATA_BLOB out;
61 : };
62 :
63 : static void kdc_udp_call_proxy_done(struct tevent_req *subreq);
64 : static void kdc_udp_call_sendto_done(struct tevent_req *subreq);
65 :
66 : static void kdc_tcp_call_writev_done(struct tevent_req *subreq);
67 : static void kdc_tcp_call_proxy_done(struct tevent_req *subreq);
68 :
69 54139 : static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdc_conn,
70 : const char *reason)
71 : {
72 54139 : stream_terminate_connection(kdc_conn->conn, reason);
73 54139 : }
74 :
75 0 : static NTSTATUS kdc_proxy_unavailable_error(struct kdc_server *kdc,
76 : TALLOC_CTX *mem_ctx,
77 : DATA_BLOB *out)
78 : {
79 : krb5_error_code code;
80 : krb5_data enc_error;
81 :
82 0 : code = smb_krb5_mk_error(kdc->smb_krb5_context->krb5_context,
83 : KRB5KDC_ERR_SVC_UNAVAILABLE,
84 : NULL,
85 : NULL,
86 : NULL,
87 : NULL,
88 : &enc_error);
89 0 : if (code != 0) {
90 0 : DBG_WARNING("Unable to form krb5 error reply\n");
91 0 : return NT_STATUS_INTERNAL_ERROR;
92 : }
93 :
94 0 : *out = data_blob_talloc(mem_ctx, enc_error.data, enc_error.length);
95 0 : smb_krb5_free_data_contents(kdc->smb_krb5_context->krb5_context,
96 : &enc_error);
97 0 : if (!out->data) {
98 0 : return NT_STATUS_NO_MEMORY;
99 : }
100 :
101 0 : return NT_STATUS_OK;
102 : }
103 :
104 16922 : static void kdc_udp_call_loop(struct tevent_req *subreq)
105 : {
106 16922 : struct kdc_udp_socket *sock = tevent_req_callback_data(subreq,
107 : struct kdc_udp_socket);
108 : struct kdc_udp_call *call;
109 : uint8_t *buf;
110 : ssize_t len;
111 : int sys_errno;
112 : kdc_code ret;
113 :
114 16922 : call = talloc(sock, struct kdc_udp_call);
115 16922 : if (call == NULL) {
116 0 : talloc_free(call);
117 0 : goto done;
118 : }
119 16922 : call->sock = sock;
120 :
121 16922 : len = tdgram_recvfrom_recv(subreq, &sys_errno,
122 : call, &buf, &call->src);
123 16922 : TALLOC_FREE(subreq);
124 16922 : if (len == -1) {
125 0 : talloc_free(call);
126 0 : goto done;
127 : }
128 :
129 16922 : call->in.data = buf;
130 16922 : call->in.length = len;
131 :
132 16922 : DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n",
133 : (long)call->in.length,
134 : tsocket_address_string(call->src, call)));
135 :
136 : /* Call krb5 */
137 33844 : ret = sock->kdc_socket->process(sock->kdc_socket->kdc,
138 : call,
139 : &call->in,
140 : &call->out,
141 : call->src,
142 16922 : sock->kdc_socket->local_address,
143 : 1 /* Datagram */);
144 16922 : if (ret == KDC_ERROR) {
145 0 : talloc_free(call);
146 0 : goto done;
147 : }
148 :
149 16922 : if (ret == KDC_PROXY_REQUEST) {
150 : uint16_t port;
151 :
152 939 : if (!sock->kdc_socket->kdc->am_rodc) {
153 0 : DEBUG(0,("kdc_udp_call_loop: proxying requested when not RODC"));
154 0 : talloc_free(call);
155 0 : goto done;
156 : }
157 :
158 939 : port = tsocket_address_inet_port(sock->kdc_socket->local_address);
159 :
160 2817 : subreq = kdc_udp_proxy_send(call,
161 939 : sock->kdc_socket->kdc->task->event_ctx,
162 939 : sock->kdc_socket->kdc,
163 : port,
164 : call->in);
165 939 : if (subreq == NULL) {
166 0 : talloc_free(call);
167 0 : goto done;
168 : }
169 939 : tevent_req_set_callback(subreq, kdc_udp_call_proxy_done, call);
170 939 : goto done;
171 : }
172 :
173 47949 : subreq = tdgram_sendto_queue_send(call,
174 15983 : sock->kdc_socket->kdc->task->event_ctx,
175 : sock->dgram,
176 : sock->send_queue,
177 15983 : call->out.data,
178 : call->out.length,
179 : call->src);
180 15983 : if (subreq == NULL) {
181 0 : talloc_free(call);
182 0 : goto done;
183 : }
184 15983 : tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call);
185 :
186 16922 : done:
187 33844 : subreq = tdgram_recvfrom_send(sock,
188 16922 : sock->kdc_socket->kdc->task->event_ctx,
189 : sock->dgram);
190 16922 : if (subreq == NULL) {
191 0 : task_server_terminate(sock->kdc_socket->kdc->task,
192 : "no memory for tdgram_recvfrom_send",
193 : true);
194 0 : return;
195 : }
196 16922 : tevent_req_set_callback(subreq, kdc_udp_call_loop, sock);
197 : }
198 :
199 939 : static void kdc_udp_call_proxy_done(struct tevent_req *subreq)
200 : {
201 939 : struct kdc_udp_call *call =
202 939 : tevent_req_callback_data(subreq,
203 : struct kdc_udp_call);
204 : NTSTATUS status;
205 :
206 939 : status = kdc_udp_proxy_recv(subreq, call, &call->out);
207 939 : TALLOC_FREE(subreq);
208 939 : if (!NT_STATUS_IS_OK(status)) {
209 : /* generate an error packet */
210 0 : status = kdc_proxy_unavailable_error(call->sock->kdc_socket->kdc,
211 : call, &call->out);
212 : }
213 :
214 939 : if (!NT_STATUS_IS_OK(status)) {
215 0 : talloc_free(call);
216 0 : return;
217 : }
218 :
219 3756 : subreq = tdgram_sendto_queue_send(call,
220 939 : call->sock->kdc_socket->kdc->task->event_ctx,
221 939 : call->sock->dgram,
222 939 : call->sock->send_queue,
223 939 : call->out.data,
224 : call->out.length,
225 : call->src);
226 939 : if (subreq == NULL) {
227 0 : talloc_free(call);
228 0 : return;
229 : }
230 :
231 939 : tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call);
232 : }
233 :
234 16922 : static void kdc_udp_call_sendto_done(struct tevent_req *subreq)
235 : {
236 16922 : struct kdc_udp_call *call = tevent_req_callback_data(subreq,
237 : struct kdc_udp_call);
238 : int sys_errno;
239 :
240 16922 : tdgram_sendto_queue_recv(subreq, &sys_errno);
241 :
242 : /* We don't care about errors */
243 :
244 16922 : talloc_free(call);
245 16922 : }
246 :
247 108278 : static void kdc_tcp_call_loop(struct tevent_req *subreq)
248 : {
249 108278 : struct kdc_tcp_connection *kdc_conn = tevent_req_callback_data(subreq,
250 : struct kdc_tcp_connection);
251 : struct kdc_tcp_call *call;
252 : NTSTATUS status;
253 : kdc_code ret;
254 :
255 108278 : call = talloc(kdc_conn, struct kdc_tcp_call);
256 108278 : if (call == NULL) {
257 0 : kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
258 : "no memory for kdc_tcp_call");
259 6 : return;
260 : }
261 108278 : call->kdc_conn = kdc_conn;
262 :
263 108278 : status = tstream_read_pdu_blob_recv(subreq,
264 : call,
265 : &call->in);
266 108278 : TALLOC_FREE(subreq);
267 108278 : if (!NT_STATUS_IS_OK(status)) {
268 : const char *reason;
269 :
270 54139 : reason = talloc_asprintf(call, "kdc_tcp_call_loop: "
271 : "tstream_read_pdu_blob_recv() - %s",
272 : nt_errstr(status));
273 54139 : if (!reason) {
274 0 : reason = nt_errstr(status);
275 : }
276 :
277 54139 : kdc_tcp_terminate_connection(kdc_conn, reason);
278 54139 : return;
279 : }
280 :
281 54139 : DEBUG(10,("Received krb5 TCP packet of length %lu from %s\n",
282 : (long) call->in.length,
283 : tsocket_address_string(kdc_conn->conn->remote_address, call)));
284 :
285 : /* skip length header */
286 54139 : call->in.data +=4;
287 54139 : call->in.length -= 4;
288 :
289 : /* Call krb5 */
290 162405 : ret = kdc_conn->kdc_socket->process(kdc_conn->kdc_socket->kdc,
291 : call,
292 : &call->in,
293 : &call->out,
294 54139 : kdc_conn->conn->remote_address,
295 54139 : kdc_conn->conn->local_address,
296 : 0 /* Stream */);
297 54139 : if (ret == KDC_ERROR) {
298 0 : kdc_tcp_terminate_connection(kdc_conn,
299 : "kdc_tcp_call_loop: process function failed");
300 0 : return;
301 : }
302 :
303 54139 : if (ret == KDC_PROXY_REQUEST) {
304 : uint16_t port;
305 :
306 2114 : if (!kdc_conn->kdc_socket->kdc->am_rodc) {
307 0 : kdc_tcp_terminate_connection(kdc_conn,
308 : "kdc_tcp_call_loop: proxying requested when not RODC");
309 0 : return;
310 : }
311 2114 : port = tsocket_address_inet_port(kdc_conn->conn->local_address);
312 :
313 6342 : subreq = kdc_tcp_proxy_send(call,
314 2114 : kdc_conn->conn->event.ctx,
315 2114 : kdc_conn->kdc_socket->kdc,
316 : port,
317 : call->in);
318 2114 : if (subreq == NULL) {
319 0 : kdc_tcp_terminate_connection(kdc_conn,
320 : "kdc_tcp_call_loop: kdc_tcp_proxy_send failed");
321 0 : return;
322 : }
323 2114 : tevent_req_set_callback(subreq, kdc_tcp_call_proxy_done, call);
324 2114 : return;
325 : }
326 :
327 : /* First add the length of the out buffer */
328 52025 : RSIVAL(call->out_hdr, 0, call->out.length);
329 52025 : call->out_iov[0].iov_base = (char *) call->out_hdr;
330 52025 : call->out_iov[0].iov_len = 4;
331 :
332 52025 : call->out_iov[1].iov_base = (char *) call->out.data;
333 52025 : call->out_iov[1].iov_len = call->out.length;
334 :
335 104044 : subreq = tstream_writev_queue_send(call,
336 52025 : kdc_conn->conn->event.ctx,
337 : kdc_conn->tstream,
338 : kdc_conn->send_queue,
339 52025 : call->out_iov, 2);
340 52025 : if (subreq == NULL) {
341 0 : kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
342 : "no memory for tstream_writev_queue_send");
343 0 : return;
344 : }
345 52025 : tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call);
346 :
347 : /*
348 : * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
349 : * packet_full_request_u32 provides the pdu length then.
350 : */
351 104044 : subreq = tstream_read_pdu_blob_send(kdc_conn,
352 52025 : kdc_conn->conn->event.ctx,
353 : kdc_conn->tstream,
354 : 4, /* initial_read_size */
355 : packet_full_request_u32,
356 : kdc_conn);
357 52025 : if (subreq == NULL) {
358 0 : kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
359 : "no memory for tstream_read_pdu_blob_send");
360 0 : return;
361 : }
362 52025 : tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn);
363 : }
364 :
365 2114 : static void kdc_tcp_call_proxy_done(struct tevent_req *subreq)
366 : {
367 2114 : struct kdc_tcp_call *call = tevent_req_callback_data(subreq,
368 : struct kdc_tcp_call);
369 2114 : struct kdc_tcp_connection *kdc_conn = call->kdc_conn;
370 : NTSTATUS status;
371 :
372 2114 : status = kdc_tcp_proxy_recv(subreq, call, &call->out);
373 2114 : TALLOC_FREE(subreq);
374 2114 : if (!NT_STATUS_IS_OK(status)) {
375 : /* generate an error packet */
376 0 : status = kdc_proxy_unavailable_error(kdc_conn->kdc_socket->kdc,
377 : call, &call->out);
378 : }
379 :
380 2114 : if (!NT_STATUS_IS_OK(status)) {
381 : const char *reason;
382 :
383 0 : reason = talloc_asprintf(call, "kdc_tcp_call_proxy_done: "
384 : "kdc_proxy_unavailable_error - %s",
385 : nt_errstr(status));
386 0 : if (!reason) {
387 0 : reason = "kdc_tcp_call_proxy_done: kdc_proxy_unavailable_error() failed";
388 : }
389 :
390 0 : kdc_tcp_terminate_connection(call->kdc_conn, reason);
391 0 : return;
392 : }
393 :
394 : /* First add the length of the out buffer */
395 2114 : RSIVAL(call->out_hdr, 0, call->out.length);
396 2114 : call->out_iov[0].iov_base = (char *) call->out_hdr;
397 2114 : call->out_iov[0].iov_len = 4;
398 :
399 2114 : call->out_iov[1].iov_base = (char *) call->out.data;
400 2114 : call->out_iov[1].iov_len = call->out.length;
401 :
402 4228 : subreq = tstream_writev_queue_send(call,
403 2114 : kdc_conn->conn->event.ctx,
404 : kdc_conn->tstream,
405 : kdc_conn->send_queue,
406 2114 : call->out_iov, 2);
407 2114 : if (subreq == NULL) {
408 0 : kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
409 : "no memory for tstream_writev_queue_send");
410 0 : return;
411 : }
412 2114 : tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call);
413 :
414 : /*
415 : * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
416 : * packet_full_request_u32 provides the pdu length then.
417 : */
418 4228 : subreq = tstream_read_pdu_blob_send(kdc_conn,
419 2114 : kdc_conn->conn->event.ctx,
420 : kdc_conn->tstream,
421 : 4, /* initial_read_size */
422 : packet_full_request_u32,
423 : kdc_conn);
424 2114 : if (subreq == NULL) {
425 0 : kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
426 : "no memory for tstream_read_pdu_blob_send");
427 0 : return;
428 : }
429 2114 : tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn);
430 : }
431 :
432 54139 : static void kdc_tcp_call_writev_done(struct tevent_req *subreq)
433 : {
434 54139 : struct kdc_tcp_call *call = tevent_req_callback_data(subreq,
435 : struct kdc_tcp_call);
436 : int sys_errno;
437 : int rc;
438 :
439 54139 : rc = tstream_writev_queue_recv(subreq, &sys_errno);
440 54139 : TALLOC_FREE(subreq);
441 54139 : if (rc == -1) {
442 : const char *reason;
443 :
444 0 : reason = talloc_asprintf(call, "kdc_tcp_call_writev_done: "
445 : "tstream_writev_queue_recv() - %d:%s",
446 : sys_errno, strerror(sys_errno));
447 0 : if (!reason) {
448 0 : reason = "kdc_tcp_call_writev_done: tstream_writev_queue_recv() failed";
449 : }
450 :
451 0 : kdc_tcp_terminate_connection(call->kdc_conn, reason);
452 0 : return;
453 : }
454 :
455 : /* We don't care about errors */
456 :
457 54139 : talloc_free(call);
458 : }
459 :
460 : /*
461 : called when we get a new connection
462 : */
463 54139 : static void kdc_tcp_accept(struct stream_connection *conn)
464 : {
465 : struct kdc_socket *kdc_socket;
466 : struct kdc_tcp_connection *kdc_conn;
467 : struct tevent_req *subreq;
468 : int rc;
469 :
470 54139 : kdc_conn = talloc_zero(conn, struct kdc_tcp_connection);
471 54139 : if (kdc_conn == NULL) {
472 0 : stream_terminate_connection(conn,
473 : "kdc_tcp_accept: out of memory");
474 0 : return;
475 : }
476 :
477 54139 : kdc_conn->send_queue = tevent_queue_create(conn, "kdc_tcp_accept");
478 54139 : if (kdc_conn->send_queue == NULL) {
479 0 : stream_terminate_connection(conn,
480 : "kdc_tcp_accept: out of memory");
481 0 : return;
482 : }
483 :
484 54139 : kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket);
485 :
486 54139 : TALLOC_FREE(conn->event.fde);
487 :
488 54139 : rc = tstream_bsd_existing_socket(kdc_conn,
489 : socket_get_fd(conn->socket),
490 : &kdc_conn->tstream);
491 54139 : if (rc < 0) {
492 0 : stream_terminate_connection(conn,
493 : "kdc_tcp_accept: out of memory");
494 0 : return;
495 : }
496 :
497 54139 : kdc_conn->conn = conn;
498 54139 : kdc_conn->kdc_socket = kdc_socket;
499 54139 : conn->private_data = kdc_conn;
500 :
501 : /*
502 : * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
503 : * packet_full_request_u32 provides the pdu length then.
504 : */
505 108272 : subreq = tstream_read_pdu_blob_send(kdc_conn,
506 54139 : kdc_conn->conn->event.ctx,
507 : kdc_conn->tstream,
508 : 4, /* initial_read_size */
509 : packet_full_request_u32,
510 : kdc_conn);
511 54139 : if (subreq == NULL) {
512 0 : kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_accept: "
513 : "no memory for tstream_read_pdu_blob_send");
514 0 : return;
515 : }
516 54139 : tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn);
517 : }
518 :
519 0 : static void kdc_tcp_recv(struct stream_connection *conn, uint16_t flags)
520 : {
521 0 : struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
522 : struct kdc_tcp_connection);
523 : /* this should never be triggered! */
524 0 : kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_recv: called");
525 0 : }
526 :
527 0 : static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags)
528 : {
529 0 : struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
530 : struct kdc_tcp_connection);
531 : /* this should never be triggered! */
532 0 : kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_send: called");
533 0 : }
534 :
535 : static const struct stream_server_ops kdc_tcp_stream_ops = {
536 : .name = "kdc_tcp",
537 : .accept_connection = kdc_tcp_accept,
538 : .recv_handler = kdc_tcp_recv,
539 : .send_handler = kdc_tcp_send
540 : };
541 :
542 : /*
543 : * Start listening on the given address
544 : */
545 316 : NTSTATUS kdc_add_socket(struct kdc_server *kdc,
546 : const struct model_ops *model_ops,
547 : const char *name,
548 : const char *address,
549 : uint16_t port,
550 : kdc_process_fn_t process,
551 : bool udp_only)
552 : {
553 : struct kdc_socket *kdc_socket;
554 : struct kdc_udp_socket *kdc_udp_socket;
555 : struct tevent_req *udpsubreq;
556 : NTSTATUS status;
557 : int ret;
558 :
559 316 : kdc_socket = talloc(kdc, struct kdc_socket);
560 316 : NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
561 :
562 316 : kdc_socket->kdc = kdc;
563 316 : kdc_socket->process = process;
564 :
565 316 : ret = tsocket_address_inet_from_strings(kdc_socket, "ip",
566 : address, port,
567 : &kdc_socket->local_address);
568 316 : if (ret != 0) {
569 0 : status = map_nt_error_from_unix_common(errno);
570 0 : return status;
571 : }
572 :
573 316 : if (!udp_only) {
574 608 : status = stream_setup_socket(kdc->task,
575 164 : kdc->task->event_ctx,
576 164 : kdc->task->lp_ctx,
577 : model_ops,
578 : &kdc_tcp_stream_ops,
579 : "ip", address, &port,
580 164 : lpcfg_socket_options(kdc->task->lp_ctx),
581 : kdc_socket,
582 164 : kdc->task->process_context);
583 164 : if (!NT_STATUS_IS_OK(status)) {
584 0 : DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
585 : address, port, nt_errstr(status)));
586 0 : talloc_free(kdc_socket);
587 0 : return status;
588 : }
589 : }
590 :
591 316 : kdc_udp_socket = talloc(kdc_socket, struct kdc_udp_socket);
592 316 : NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket);
593 :
594 316 : kdc_udp_socket->kdc_socket = kdc_socket;
595 :
596 316 : ret = tdgram_inet_udp_socket(kdc_socket->local_address,
597 : NULL,
598 : kdc_udp_socket,
599 : &kdc_udp_socket->dgram);
600 316 : if (ret != 0) {
601 0 : status = map_nt_error_from_unix_common(errno);
602 0 : DEBUG(0,("Failed to bind to %s:%u UDP - %s\n",
603 : address, port, nt_errstr(status)));
604 0 : return status;
605 : }
606 :
607 316 : kdc_udp_socket->send_queue = tevent_queue_create(kdc_udp_socket,
608 : "kdc_udp_send_queue");
609 316 : NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket->send_queue);
610 :
611 596 : udpsubreq = tdgram_recvfrom_send(kdc_udp_socket,
612 316 : kdc->task->event_ctx,
613 : kdc_udp_socket->dgram);
614 316 : NT_STATUS_HAVE_NO_MEMORY(udpsubreq);
615 316 : tevent_req_set_callback(udpsubreq, kdc_udp_call_loop, kdc_udp_socket);
616 :
617 316 : return NT_STATUS_OK;
618 : }
|