source: vendor/current/source4/lib/messaging/messaging.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 26.0 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Samba internal messaging functions
5
6 Copyright (C) Andrew Tridgell 2004
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 "lib/events/events.h"
24#include "system/filesys.h"
25#include "messaging/messaging.h"
26#include "../lib/util/dlinklist.h"
27#include "lib/socket/socket.h"
28#include "librpc/gen_ndr/ndr_irpc.h"
29#include "lib/messaging/irpc.h"
30#include "../lib/util/unix_privs.h"
31#include "librpc/rpc/dcerpc.h"
32#include "cluster/cluster.h"
33#include "../lib/util/tevent_ntstatus.h"
34#include "lib/param/param.h"
35#include "lib/util/server_id_db.h"
36#include "lib/util/talloc_report.h"
37#include "../source3/lib/messages_dgm.h"
38#include "../source3/lib/messages_dgm_ref.h"
39#include "../source3/lib/messages_util.h"
40#include <tdb.h>
41
42/* change the message version with any incompatible changes in the protocol */
43#define IMESSAGING_VERSION 1
44
45/*
46 a pending irpc call
47*/
48struct irpc_request {
49 struct imessaging_context *msg_ctx;
50 int callid;
51 struct {
52 void (*handler)(struct irpc_request *irpc, struct irpc_message *m);
53 void *private_data;
54 } incoming;
55};
56
57struct imessaging_context {
58 struct imessaging_context *prev, *next;
59 struct server_id server_id;
60 const char *sock_dir;
61 const char *lock_dir;
62 struct dispatch_fn **dispatch;
63 uint32_t num_types;
64 struct idr_context *dispatch_tree;
65 struct irpc_list *irpc;
66 struct idr_context *idr;
67 struct server_id_db *names;
68 struct timeval start_time;
69 void *msg_dgm_ref;
70};
71
72/* we have a linked list of dispatch handlers for each msg_type that
73 this messaging server can deal with */
74struct dispatch_fn {
75 struct dispatch_fn *next, *prev;
76 uint32_t msg_type;
77 void *private_data;
78 msg_callback_t fn;
79};
80
81/* an individual message */
82
83static void irpc_handler(struct imessaging_context *, void *,
84 uint32_t, struct server_id, DATA_BLOB *);
85
86
87/*
88 A useful function for testing the message system.
89*/
90static void ping_message(struct imessaging_context *msg, void *private_data,
91 uint32_t msg_type, struct server_id src, DATA_BLOB *data)
92{
93 struct server_id_buf idbuf;
94 DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
95 server_id_str_buf(src, &idbuf), (int)data->length,
96 data->data?(const char *)data->data:""));
97 imessaging_send(msg, src, MSG_PONG, data);
98}
99
100static void pool_message(struct imessaging_context *msg, void *private_data,
101 uint32_t msg_type, struct server_id src,
102 DATA_BLOB *data)
103{
104 char *report;
105
106 report = talloc_report_str(msg, NULL);
107
108 if (report != NULL) {
109 DATA_BLOB blob = { .data = (uint8_t *)report,
110 .length = talloc_get_size(report) - 1};
111 imessaging_send(msg, src, MSG_POOL_USAGE, &blob);
112 }
113 talloc_free(report);
114}
115
116/*
117 return uptime of messaging server via irpc
118*/
119static NTSTATUS irpc_uptime(struct irpc_message *msg,
120 struct irpc_uptime *r)
121{
122 struct imessaging_context *ctx = talloc_get_type(msg->private_data, struct imessaging_context);
123 *r->out.start_time = timeval_to_nttime(&ctx->start_time);
124 return NT_STATUS_OK;
125}
126
127static struct dispatch_fn *imessaging_find_dispatch(
128 struct imessaging_context *msg, uint32_t msg_type)
129{
130 /* temporary IDs use an idtree, the rest use a array of pointers */
131 if (msg_type >= MSG_TMP_BASE) {
132 return (struct dispatch_fn *)idr_find(msg->dispatch_tree,
133 msg_type);
134 }
135 if (msg_type < msg->num_types) {
136 return msg->dispatch[msg_type];
137 }
138 return NULL;
139}
140
141/*
142 Register a dispatch function for a particular message type.
143*/
144NTSTATUS imessaging_register(struct imessaging_context *msg, void *private_data,
145 uint32_t msg_type, msg_callback_t fn)
146{
147 struct dispatch_fn *d;
148
149 /* possibly expand dispatch array */
150 if (msg_type >= msg->num_types) {
151 struct dispatch_fn **dp;
152 int i;
153 dp = talloc_realloc(msg, msg->dispatch, struct dispatch_fn *, msg_type+1);
154 NT_STATUS_HAVE_NO_MEMORY(dp);
155 msg->dispatch = dp;
156 for (i=msg->num_types;i<=msg_type;i++) {
157 msg->dispatch[i] = NULL;
158 }
159 msg->num_types = msg_type+1;
160 }
161
162 d = talloc_zero(msg->dispatch, struct dispatch_fn);
163 NT_STATUS_HAVE_NO_MEMORY(d);
164 d->msg_type = msg_type;
165 d->private_data = private_data;
166 d->fn = fn;
167
168 DLIST_ADD(msg->dispatch[msg_type], d);
169
170 return NT_STATUS_OK;
171}
172
173/*
174 register a temporary message handler. The msg_type is allocated
175 above MSG_TMP_BASE
176*/
177NTSTATUS imessaging_register_tmp(struct imessaging_context *msg, void *private_data,
178 msg_callback_t fn, uint32_t *msg_type)
179{
180 struct dispatch_fn *d;
181 int id;
182
183 d = talloc_zero(msg->dispatch, struct dispatch_fn);
184 NT_STATUS_HAVE_NO_MEMORY(d);
185 d->private_data = private_data;
186 d->fn = fn;
187
188 id = idr_get_new_above(msg->dispatch_tree, d, MSG_TMP_BASE, UINT16_MAX);
189 if (id == -1) {
190 talloc_free(d);
191 return NT_STATUS_TOO_MANY_CONTEXT_IDS;
192 }
193
194 d->msg_type = (uint32_t)id;
195 (*msg_type) = d->msg_type;
196
197 return NT_STATUS_OK;
198}
199
200/*
201 De-register the function for a particular message type.
202*/
203void imessaging_deregister(struct imessaging_context *msg, uint32_t msg_type, void *private_data)
204{
205 struct dispatch_fn *d, *next;
206
207 if (msg_type >= msg->num_types) {
208 d = (struct dispatch_fn *)idr_find(msg->dispatch_tree,
209 msg_type);
210 if (!d) return;
211 idr_remove(msg->dispatch_tree, msg_type);
212 talloc_free(d);
213 return;
214 }
215
216 for (d = msg->dispatch[msg_type]; d; d = next) {
217 next = d->next;
218 if (d->private_data == private_data) {
219 DLIST_REMOVE(msg->dispatch[msg_type], d);
220 talloc_free(d);
221 }
222 }
223}
224
225/*
226 Send a message to a particular server
227*/
228NTSTATUS imessaging_send(struct imessaging_context *msg, struct server_id server,
229 uint32_t msg_type, const DATA_BLOB *data)
230{
231 uint8_t hdr[MESSAGE_HDR_LENGTH];
232 struct iovec iov[2];
233 int num_iov, ret;
234 pid_t pid;
235 void *priv;
236
237 if (!cluster_node_equal(&msg->server_id, &server)) {
238 /* No cluster in source4... */
239 return NT_STATUS_OK;
240 }
241
242 message_hdr_put(hdr, msg_type, msg->server_id, server);
243
244 iov[0] = (struct iovec) { .iov_base = &hdr, .iov_len = sizeof(hdr) };
245 num_iov = 1;
246
247 if (data != NULL) {
248 iov[1] = (struct iovec) { .iov_base = data->data,
249 .iov_len = data->length };
250 num_iov += 1;
251 }
252
253 pid = server.pid;
254 if (pid == 0) {
255 pid = getpid();
256 }
257
258 priv = root_privileges();
259 ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
260 TALLOC_FREE(priv);
261 if (ret != 0) {
262 return map_nt_error_from_unix_common(ret);
263 }
264 return NT_STATUS_OK;
265}
266
267/*
268 Send a message to a particular server, with the message containing a single pointer
269*/
270NTSTATUS imessaging_send_ptr(struct imessaging_context *msg, struct server_id server,
271 uint32_t msg_type, void *ptr)
272{
273 DATA_BLOB blob;
274
275 blob.data = (uint8_t *)&ptr;
276 blob.length = sizeof(void *);
277
278 return imessaging_send(msg, server, msg_type, &blob);
279}
280
281
282/*
283 remove our messaging socket and database entry
284*/
285int imessaging_cleanup(struct imessaging_context *msg)
286{
287 if (!msg) {
288 return 0;
289 }
290 return 0;
291}
292
293static void imessaging_dgm_recv(const uint8_t *buf, size_t buf_len,
294 int *fds, size_t num_fds,
295 void *private_data);
296
297/*
298 create the listening socket and setup the dispatcher
299
300 use auto_remove=true when you want a destructor to remove the
301 associated messaging socket and database entry on talloc free. Don't
302 use this in processes that may fork and a child may talloc free this
303 memory
304*/
305struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
306 struct loadparm_context *lp_ctx,
307 struct server_id server_id,
308 struct tevent_context *ev,
309 bool auto_remove)
310{
311 struct imessaging_context *msg;
312 bool ok;
313 int ret;
314 const char *lock_dir = NULL;
315 int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
316
317 if (ev == NULL) {
318 return NULL;
319 }
320
321 msg = talloc_zero(mem_ctx, struct imessaging_context);
322 if (msg == NULL) {
323 return NULL;
324 }
325
326 /* create the messaging directory if needed */
327
328 lock_dir = lpcfg_lock_directory(lp_ctx);
329 if (lock_dir == NULL) {
330 goto fail;
331 }
332
333 msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
334 if (msg->sock_dir == NULL) {
335 goto fail;
336 }
337 ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
338 if (!ok) {
339 goto fail;
340 }
341
342 msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
343 if (msg->lock_dir == NULL) {
344 goto fail;
345 }
346 ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
347 if (!ok) {
348 goto fail;
349 }
350
351 msg->msg_dgm_ref = messaging_dgm_ref(
352 msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
353 imessaging_dgm_recv, msg, &ret);
354
355 if (msg->msg_dgm_ref == NULL) {
356 goto fail;
357 }
358
359 msg->server_id = server_id;
360 msg->idr = idr_init(msg);
361 if (msg->idr == NULL) {
362 goto fail;
363 }
364
365 msg->dispatch_tree = idr_init(msg);
366 if (msg->dispatch_tree == NULL) {
367 goto fail;
368 }
369
370 msg->start_time = timeval_current();
371
372 tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
373
374 msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
375 if (msg->names == NULL) {
376 goto fail;
377 }
378
379 if (auto_remove) {
380 talloc_set_destructor(msg, imessaging_cleanup);
381 }
382
383 imessaging_register(msg, NULL, MSG_PING, ping_message);
384 imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE, pool_message);
385 imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
386 IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
387
388 return msg;
389fail:
390 talloc_free(msg);
391 return NULL;
392}
393
394static void imessaging_dgm_recv(const uint8_t *buf, size_t buf_len,
395 int *fds, size_t num_fds,
396 void *private_data)
397{
398 struct imessaging_context *msg = talloc_get_type_abort(
399 private_data, struct imessaging_context);
400 uint32_t msg_type;
401 struct server_id src, dst;
402 struct server_id_buf srcbuf, dstbuf;
403 DATA_BLOB data;
404
405 if (buf_len < MESSAGE_HDR_LENGTH) {
406 /* Invalid message, ignore */
407 return;
408 }
409
410 message_hdr_get(&msg_type, &src, &dst, buf);
411
412 data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
413 data.length = buf_len - MESSAGE_HDR_LENGTH;
414
415 if ((cluster_id_equal(&dst, &msg->server_id)) ||
416 ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
417 struct dispatch_fn *d, *next;
418
419 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
420 __func__,
421 server_id_str_buf(dst, &dstbuf),
422 server_id_str_buf(msg->server_id, &srcbuf),
423 (unsigned)msg_type));
424
425 d = imessaging_find_dispatch(msg, msg_type);
426
427 for (; d; d = next) {
428 next = d->next;
429 d->fn(msg, d->private_data, d->msg_type, src, &data);
430 }
431 } else {
432 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
433 __func__, (unsigned)msg_type,
434 server_id_str_buf(dst, &dstbuf),
435 server_id_str_buf(msg->server_id, &srcbuf)));
436 }
437}
438
439/*
440 A hack, for the short term until we get 'client only' messaging in place
441*/
442struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
443 struct loadparm_context *lp_ctx,
444 struct tevent_context *ev)
445{
446 struct server_id id;
447 ZERO_STRUCT(id);
448 id.pid = getpid();
449 id.task_id = generate_random();
450 id.vnn = NONCLUSTER_VNN;
451
452 /* This is because we are not in the s3 serverid database */
453 id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
454
455 return imessaging_init(mem_ctx, lp_ctx, id, ev, true);
456}
457/*
458 a list of registered irpc server functions
459*/
460struct irpc_list {
461 struct irpc_list *next, *prev;
462 struct GUID uuid;
463 const struct ndr_interface_table *table;
464 int callnum;
465 irpc_function_t fn;
466 void *private_data;
467};
468
469
470/*
471 register a irpc server function
472*/
473NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
474 const struct ndr_interface_table *table,
475 int callnum, irpc_function_t fn, void *private_data)
476{
477 struct irpc_list *irpc;
478
479 /* override an existing handler, if any */
480 for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
481 if (irpc->table == table && irpc->callnum == callnum) {
482 break;
483 }
484 }
485 if (irpc == NULL) {
486 irpc = talloc(msg_ctx, struct irpc_list);
487 NT_STATUS_HAVE_NO_MEMORY(irpc);
488 DLIST_ADD(msg_ctx->irpc, irpc);
489 }
490
491 irpc->table = table;
492 irpc->callnum = callnum;
493 irpc->fn = fn;
494 irpc->private_data = private_data;
495 irpc->uuid = irpc->table->syntax_id.uuid;
496
497 return NT_STATUS_OK;
498}
499
500
501/*
502 handle an incoming irpc reply message
503*/
504static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
505{
506 struct irpc_request *irpc;
507
508 irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
509 if (irpc == NULL) return;
510
511 irpc->incoming.handler(irpc, m);
512}
513
514/*
515 send a irpc reply
516*/
517NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
518{
519 struct ndr_push *push;
520 DATA_BLOB packet;
521 enum ndr_err_code ndr_err;
522
523 m->header.status = status;
524
525 /* setup the reply */
526 push = ndr_push_init_ctx(m->ndr);
527 if (push == NULL) {
528 status = NT_STATUS_NO_MEMORY;
529 goto failed;
530 }
531
532 m->header.flags |= IRPC_FLAG_REPLY;
533 m->header.creds.token= NULL;
534
535 /* construct the packet */
536 ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
537 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
538 status = ndr_map_error2ntstatus(ndr_err);
539 goto failed;
540 }
541
542 ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
543 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
544 status = ndr_map_error2ntstatus(ndr_err);
545 goto failed;
546 }
547
548 /* send the reply message */
549 packet = ndr_push_blob(push);
550 status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
551 if (!NT_STATUS_IS_OK(status)) goto failed;
552
553failed:
554 talloc_free(m);
555 return status;
556}
557
558/*
559 handle an incoming irpc request message
560*/
561static void irpc_handler_request(struct imessaging_context *msg_ctx,
562 struct irpc_message *m)
563{
564 struct irpc_list *i;
565 void *r;
566 enum ndr_err_code ndr_err;
567
568 for (i=msg_ctx->irpc; i; i=i->next) {
569 if (GUID_equal(&i->uuid, &m->header.uuid) &&
570 i->table->syntax_id.if_version == m->header.if_version &&
571 i->callnum == m->header.callnum) {
572 break;
573 }
574 }
575
576 if (i == NULL) {
577 /* no registered handler for this message */
578 talloc_free(m);
579 return;
580 }
581
582 /* allocate space for the structure */
583 r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
584 if (r == NULL) goto failed;
585
586 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
587
588 /* parse the request data */
589 ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
590 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
591
592 /* make the call */
593 m->private_data= i->private_data;
594 m->defer_reply = false;
595 m->no_reply = false;
596 m->msg_ctx = msg_ctx;
597 m->irpc = i;
598 m->data = r;
599
600 m->header.status = i->fn(m, r);
601
602 if (m->no_reply) {
603 /* the server function won't ever be replying to this request */
604 talloc_free(m);
605 return;
606 }
607
608 if (m->defer_reply) {
609 /* the server function has asked to defer the reply to later */
610 talloc_steal(msg_ctx, m);
611 return;
612 }
613
614 irpc_send_reply(m, m->header.status);
615 return;
616
617failed:
618 talloc_free(m);
619}
620
621/*
622 handle an incoming irpc message
623*/
624static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
625 uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
626{
627 struct irpc_message *m;
628 enum ndr_err_code ndr_err;
629
630 m = talloc(msg_ctx, struct irpc_message);
631 if (m == NULL) goto failed;
632
633 m->from = src;
634
635 m->ndr = ndr_pull_init_blob(packet, m);
636 if (m->ndr == NULL) goto failed;
637
638 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
639
640 ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
641 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
642
643 if (m->header.flags & IRPC_FLAG_REPLY) {
644 irpc_handler_reply(msg_ctx, m);
645 } else {
646 irpc_handler_request(msg_ctx, m);
647 }
648 return;
649
650failed:
651 talloc_free(m);
652}
653
654
655/*
656 destroy a irpc request
657*/
658static int irpc_destructor(struct irpc_request *irpc)
659{
660 if (irpc->callid != -1) {
661 idr_remove(irpc->msg_ctx->idr, irpc->callid);
662 irpc->callid = -1;
663 }
664
665 return 0;
666}
667
668/*
669 add a string name that this irpc server can be called on
670*/
671NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
672{
673 int ret;
674
675 ret = server_id_db_add(msg_ctx->names, name);
676 if (ret != 0) {
677 return map_nt_error_from_unix_common(ret);
678 }
679 return NT_STATUS_OK;
680}
681
682/*
683 return a list of server ids for a server name
684*/
685NTSTATUS irpc_servers_byname(struct imessaging_context *msg_ctx,
686 TALLOC_CTX *mem_ctx, const char *name,
687 unsigned *num_servers,
688 struct server_id **servers)
689{
690 int ret;
691
692 ret = server_id_db_lookup(msg_ctx->names, name, mem_ctx,
693 num_servers, servers);
694 if (ret != 0) {
695 return map_nt_error_from_unix_common(ret);
696 }
697 return NT_STATUS_OK;
698}
699
700static int all_servers_func(const char *name, unsigned num_servers,
701 const struct server_id *servers,
702 void *private_data)
703{
704 struct irpc_name_records *name_records = talloc_get_type(
705 private_data, struct irpc_name_records);
706 struct irpc_name_record *name_record;
707 int i;
708
709 name_records->names
710 = talloc_realloc(name_records, name_records->names,
711 struct irpc_name_record *, name_records->num_records+1);
712 if (!name_records->names) {
713 return -1;
714 }
715
716 name_records->names[name_records->num_records] = name_record
717 = talloc(name_records->names,
718 struct irpc_name_record);
719 if (!name_record) {
720 return -1;
721 }
722
723 name_records->num_records++;
724
725 name_record->name = talloc_strdup(name_record, name);
726 if (!name_record->name) {
727 return -1;
728 }
729
730 name_record->count = num_servers;
731 name_record->ids = talloc_array(name_record, struct server_id,
732 num_servers);
733 if (name_record->ids == NULL) {
734 return -1;
735 }
736 for (i=0;i<name_record->count;i++) {
737 name_record->ids[i] = servers[i];
738 }
739 return 0;
740}
741
742/*
743 return a list of server ids for a server name
744*/
745struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
746 TALLOC_CTX *mem_ctx)
747{
748 int ret;
749 struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
750 if (name_records == NULL) {
751 return NULL;
752 }
753
754 ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
755 name_records);
756 if (ret == -1) {
757 TALLOC_FREE(name_records);
758 return NULL;
759 }
760
761 return name_records;
762}
763
764/*
765 remove a name from a messaging context
766*/
767void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
768{
769 server_id_db_remove(msg_ctx->names, name);
770}
771
772struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
773{
774 return msg_ctx->server_id;
775}
776
777struct irpc_bh_state {
778 struct imessaging_context *msg_ctx;
779 struct server_id server_id;
780 const struct ndr_interface_table *table;
781 uint32_t timeout;
782 struct security_token *token;
783};
784
785static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
786{
787 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
788 struct irpc_bh_state);
789
790 if (!hs->msg_ctx) {
791 return false;
792 }
793
794 return true;
795}
796
797static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
798 uint32_t timeout)
799{
800 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
801 struct irpc_bh_state);
802 uint32_t old = hs->timeout;
803
804 hs->timeout = timeout;
805
806 return old;
807}
808
809struct irpc_bh_raw_call_state {
810 struct irpc_request *irpc;
811 uint32_t opnum;
812 DATA_BLOB in_data;
813 DATA_BLOB in_packet;
814 DATA_BLOB out_data;
815};
816
817static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
818 struct irpc_message *m);
819
820static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
821 struct tevent_context *ev,
822 struct dcerpc_binding_handle *h,
823 const struct GUID *object,
824 uint32_t opnum,
825 uint32_t in_flags,
826 const uint8_t *in_data,
827 size_t in_length)
828{
829 struct irpc_bh_state *hs =
830 dcerpc_binding_handle_data(h,
831 struct irpc_bh_state);
832 struct tevent_req *req;
833 struct irpc_bh_raw_call_state *state;
834 bool ok;
835 struct irpc_header header;
836 struct ndr_push *ndr;
837 NTSTATUS status;
838 enum ndr_err_code ndr_err;
839
840 req = tevent_req_create(mem_ctx, &state,
841 struct irpc_bh_raw_call_state);
842 if (req == NULL) {
843 return NULL;
844 }
845 state->opnum = opnum;
846 state->in_data.data = discard_const_p(uint8_t, in_data);
847 state->in_data.length = in_length;
848
849 ok = irpc_bh_is_connected(h);
850 if (!ok) {
851 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
852 return tevent_req_post(req, ev);
853 }
854
855 state->irpc = talloc_zero(state, struct irpc_request);
856 if (tevent_req_nomem(state->irpc, req)) {
857 return tevent_req_post(req, ev);
858 }
859
860 state->irpc->msg_ctx = hs->msg_ctx;
861 state->irpc->callid = idr_get_new(hs->msg_ctx->idr,
862 state->irpc, UINT16_MAX);
863 if (state->irpc->callid == -1) {
864 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
865 return tevent_req_post(req, ev);
866 }
867 state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
868 state->irpc->incoming.private_data = req;
869
870 talloc_set_destructor(state->irpc, irpc_destructor);
871
872 /* setup the header */
873 header.uuid = hs->table->syntax_id.uuid;
874
875 header.if_version = hs->table->syntax_id.if_version;
876 header.callid = state->irpc->callid;
877 header.callnum = state->opnum;
878 header.flags = 0;
879 header.status = NT_STATUS_OK;
880 header.creds.token= hs->token;
881
882 /* construct the irpc packet */
883 ndr = ndr_push_init_ctx(state->irpc);
884 if (tevent_req_nomem(ndr, req)) {
885 return tevent_req_post(req, ev);
886 }
887
888 ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
889 status = ndr_map_error2ntstatus(ndr_err);
890 if (!NT_STATUS_IS_OK(status)) {
891 tevent_req_nterror(req, status);
892 return tevent_req_post(req, ev);
893 }
894
895 ndr_err = ndr_push_bytes(ndr, in_data, in_length);
896 status = ndr_map_error2ntstatus(ndr_err);
897 if (!NT_STATUS_IS_OK(status)) {
898 tevent_req_nterror(req, status);
899 return tevent_req_post(req, ev);
900 }
901
902 /* and send it */
903 state->in_packet = ndr_push_blob(ndr);
904 status = imessaging_send(hs->msg_ctx, hs->server_id,
905 MSG_IRPC, &state->in_packet);
906 if (!NT_STATUS_IS_OK(status)) {
907 tevent_req_nterror(req, status);
908 return tevent_req_post(req, ev);
909 }
910
911 if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
912 /* set timeout-callback in case caller wants that */
913 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
914 if (!ok) {
915 return tevent_req_post(req, ev);
916 }
917 }
918
919 return req;
920}
921
922static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
923 struct irpc_message *m)
924{
925 struct tevent_req *req =
926 talloc_get_type_abort(irpc->incoming.private_data,
927 struct tevent_req);
928 struct irpc_bh_raw_call_state *state =
929 tevent_req_data(req,
930 struct irpc_bh_raw_call_state);
931
932 talloc_steal(state, m);
933
934 if (!NT_STATUS_IS_OK(m->header.status)) {
935 tevent_req_nterror(req, m->header.status);
936 return;
937 }
938
939 state->out_data = data_blob_talloc(state,
940 m->ndr->data + m->ndr->offset,
941 m->ndr->data_size - m->ndr->offset);
942 if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
943 tevent_req_oom(req);
944 return;
945 }
946
947 tevent_req_done(req);
948}
949
950static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
951 TALLOC_CTX *mem_ctx,
952 uint8_t **out_data,
953 size_t *out_length,
954 uint32_t *out_flags)
955{
956 struct irpc_bh_raw_call_state *state =
957 tevent_req_data(req,
958 struct irpc_bh_raw_call_state);
959 NTSTATUS status;
960
961 if (tevent_req_is_nterror(req, &status)) {
962 tevent_req_received(req);
963 return status;
964 }
965
966 *out_data = talloc_move(mem_ctx, &state->out_data.data);
967 *out_length = state->out_data.length;
968 *out_flags = 0;
969 tevent_req_received(req);
970 return NT_STATUS_OK;
971}
972
973struct irpc_bh_disconnect_state {
974 uint8_t _dummy;
975};
976
977static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
978 struct tevent_context *ev,
979 struct dcerpc_binding_handle *h)
980{
981 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
982 struct irpc_bh_state);
983 struct tevent_req *req;
984 struct irpc_bh_disconnect_state *state;
985 bool ok;
986
987 req = tevent_req_create(mem_ctx, &state,
988 struct irpc_bh_disconnect_state);
989 if (req == NULL) {
990 return NULL;
991 }
992
993 ok = irpc_bh_is_connected(h);
994 if (!ok) {
995 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
996 return tevent_req_post(req, ev);
997 }
998
999 hs->msg_ctx = NULL;
1000
1001 tevent_req_done(req);
1002 return tevent_req_post(req, ev);
1003}
1004
1005static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1006{
1007 NTSTATUS status;
1008
1009 if (tevent_req_is_nterror(req, &status)) {
1010 tevent_req_received(req);
1011 return status;
1012 }
1013
1014 tevent_req_received(req);
1015 return NT_STATUS_OK;
1016}
1017
1018static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1019{
1020 return true;
1021}
1022
1023static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1024 .name = "wbint",
1025 .is_connected = irpc_bh_is_connected,
1026 .set_timeout = irpc_bh_set_timeout,
1027 .raw_call_send = irpc_bh_raw_call_send,
1028 .raw_call_recv = irpc_bh_raw_call_recv,
1029 .disconnect_send = irpc_bh_disconnect_send,
1030 .disconnect_recv = irpc_bh_disconnect_recv,
1031
1032 .ref_alloc = irpc_bh_ref_alloc,
1033};
1034
1035/* initialise a irpc binding handle */
1036struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1037 struct imessaging_context *msg_ctx,
1038 struct server_id server_id,
1039 const struct ndr_interface_table *table)
1040{
1041 struct dcerpc_binding_handle *h;
1042 struct irpc_bh_state *hs;
1043
1044 h = dcerpc_binding_handle_create(mem_ctx,
1045 &irpc_bh_ops,
1046 NULL,
1047 table,
1048 &hs,
1049 struct irpc_bh_state,
1050 __location__);
1051 if (h == NULL) {
1052 return NULL;
1053 }
1054 hs->msg_ctx = msg_ctx;
1055 hs->server_id = server_id;
1056 hs->table = table;
1057 hs->timeout = IRPC_CALL_TIMEOUT;
1058
1059 return h;
1060}
1061
1062struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1063 struct imessaging_context *msg_ctx,
1064 const char *dest_task,
1065 const struct ndr_interface_table *table)
1066{
1067 struct dcerpc_binding_handle *h;
1068 unsigned num_sids;
1069 struct server_id *sids;
1070 struct server_id sid;
1071 NTSTATUS status;
1072
1073 /* find the server task */
1074
1075 status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1076 &num_sids, &sids);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 errno = EADDRNOTAVAIL;
1079 return NULL;
1080 }
1081 sid = sids[0];
1082 talloc_free(sids);
1083
1084 h = irpc_binding_handle(mem_ctx, msg_ctx,
1085 sid, table);
1086 if (h == NULL) {
1087 return NULL;
1088 }
1089
1090 return h;
1091}
1092
1093void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1094 struct security_token *token)
1095{
1096 struct irpc_bh_state *hs =
1097 dcerpc_binding_handle_data(h,
1098 struct irpc_bh_state);
1099
1100 hs->token = token;
1101}
Note: See TracBrowser for help on using the repository browser.