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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "system/filesys.h"
26 #include "messaging/messaging.h"
27 #include "lib/util/dlinklist.h"
28 #include "lib/socket/socket.h"
29 #include "librpc/gen_ndr/ndr_irpc.h"
30 #include "lib/messaging/irpc.h"
31 #include "db_wrap.h"
32 #include "lib/util/unix_privs.h"
33 #include "librpc/rpc/dcerpc.h"
34 #include "lib/tdb/include/tdb.h"
35 #include "lib/util/util_tdb.h"
36
37 /* change the message version with any incompatible changes in the protocol */
38 #define MESSAGING_VERSION 1
39
40 struct messaging_context {
41 uint32_t server_id;
42 struct socket_context *sock;
43 const char *base_path;
44 const char *path;
45 struct dispatch_fn **dispatch;
46 uint32_t num_types;
47 struct idr_context *dispatch_tree;
48 struct messaging_rec *pending;
49 struct irpc_list *irpc;
50 struct idr_context *idr;
51 const char **names;
52 struct timeval start_time;
53
54 struct {
55 struct event_context *ev;
56 struct fd_event *fde;
57 } event;
58 };
59
60 /* we have a linked list of dispatch handlers for each msg_type that
61 this messaging server can deal with */
62 struct dispatch_fn {
63 struct dispatch_fn *next, *prev;
64 uint32_t msg_type;
65 void *private;
66 msg_callback_t fn;
67 };
68
69 /* an individual message */
70 struct messaging_rec {
71 struct messaging_rec *next, *prev;
72 struct messaging_context *msg;
73 const char *path;
74
75 struct messaging_header {
76 uint32_t version;
77 uint32_t msg_type;
78 uint32_t from;
79 uint32_t to;
80 uint32_t length;
81 } *header;
82
83 DATA_BLOB packet;
84 };
85
86
87 static void irpc_handler(struct messaging_context *, void *,
88 uint32_t, uint32_t, DATA_BLOB *);
89
90
91 /*
92 A useful function for testing the message system.
93 */
ping_message(struct messaging_context * msg,void * private,uint32_t msg_type,uint32_t src,DATA_BLOB * data)94 static void ping_message(struct messaging_context *msg, void *private,
95 uint32_t msg_type, uint32_t src, DATA_BLOB *data)
96 {
97 DEBUG(1,("INFO: Received PING message from server %u [%.*s]\n",
98 (uint_t)src, (int)data->length,
99 data->data?(const char *)data->data:""));
100 messaging_send(msg, src, MSG_PONG, data);
101 }
102
103 /*
104 return uptime of messaging server via irpc
105 */
irpc_uptime(struct irpc_message * msg,struct irpc_uptime * r)106 static NTSTATUS irpc_uptime(struct irpc_message *msg,
107 struct irpc_uptime *r)
108 {
109 struct messaging_context *ctx = talloc_get_type(msg->private, struct messaging_context);
110 *r->out.start_time = timeval_to_nttime(&ctx->start_time);
111 return NT_STATUS_OK;
112 }
113
114 /*
115 return the path to a messaging socket
116 */
messaging_path(struct messaging_context * msg,uint32_t server_id)117 static char *messaging_path(struct messaging_context *msg, uint32_t server_id)
118 {
119 return talloc_asprintf(msg, "%s/msg.%u", msg->base_path, (unsigned)server_id);
120 }
121
122 /*
123 dispatch a fully received message
124
125 note that this deliberately can match more than one message handler
126 per message. That allows a single messasging context to register
127 (for example) a debug handler for more than one piece of code
128 */
messaging_dispatch(struct messaging_context * msg,struct messaging_rec * rec)129 static void messaging_dispatch(struct messaging_context *msg, struct messaging_rec *rec)
130 {
131 struct dispatch_fn *d, *next;
132
133 /* temporary IDs use an idtree, the rest use a array of pointers */
134 if (rec->header->msg_type >= MSG_TMP_BASE) {
135 d = idr_find(msg->dispatch_tree, rec->header->msg_type);
136 } else if (rec->header->msg_type < msg->num_types) {
137 d = msg->dispatch[rec->header->msg_type];
138 } else {
139 d = NULL;
140 }
141
142 for (; d; d = next) {
143 DATA_BLOB data;
144 next = d->next;
145 data.data = rec->packet.data + sizeof(*rec->header);
146 data.length = rec->header->length;
147 d->fn(msg, d->private, d->msg_type, rec->header->from, &data);
148 }
149 rec->header->length = 0;
150 }
151
152
153 /*
154 try to send the message
155 */
try_send(struct messaging_rec * rec)156 static NTSTATUS try_send(struct messaging_rec *rec)
157 {
158 struct messaging_context *msg = rec->msg;
159 size_t nsent;
160 void *priv;
161 NTSTATUS status;
162 struct socket_address *path;
163
164 /* rec->path is the path of the *other* socket, where we want
165 * this to end up */
166 path = socket_address_from_strings(msg, msg->sock->backend_name,
167 rec->path, 0);
168 if (!path) {
169 return NT_STATUS_NO_MEMORY;
170 }
171
172 /* we send with privileges so messages work from any context */
173 priv = root_privileges();
174 status = socket_sendto(msg->sock, &rec->packet, &nsent, path);
175 talloc_free(path);
176 talloc_free(priv);
177
178 return status;
179 }
180
181 /*
182 handle a socket write event
183 */
messaging_send_handler(struct messaging_context * msg)184 static void messaging_send_handler(struct messaging_context *msg)
185 {
186 while (msg->pending) {
187 struct messaging_rec *rec = msg->pending;
188 NTSTATUS status;
189 status = try_send(rec);
190 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
191 break;
192 }
193 if (!NT_STATUS_IS_OK(status)) {
194 DEBUG(1,("messaging: Lost message from %u to %u of type %u - %s\n",
195 rec->header->from, rec->header->to, rec->header->msg_type,
196 nt_errstr(status)));
197 }
198 DLIST_REMOVE(msg->pending, rec);
199 talloc_free(rec);
200 }
201 if (msg->pending == NULL) {
202 EVENT_FD_NOT_WRITEABLE(msg->event.fde);
203 }
204 }
205
206 /*
207 handle a new incoming packet
208 */
messaging_recv_handler(struct messaging_context * msg)209 static void messaging_recv_handler(struct messaging_context *msg)
210 {
211 struct messaging_rec *rec;
212 NTSTATUS status;
213 DATA_BLOB packet;
214 size_t msize;
215
216 /* see how many bytes are in the next packet */
217 status = socket_pending(msg->sock, &msize);
218 if (!NT_STATUS_IS_OK(status)) {
219 DEBUG(0,("socket_pending failed in messaging - %s\n",
220 nt_errstr(status)));
221 return;
222 }
223
224 packet = data_blob_talloc(msg, NULL, msize);
225 if (packet.data == NULL) {
226 /* assume this is temporary and retry */
227 return;
228 }
229
230 status = socket_recv(msg->sock, packet.data, msize, &msize);
231 if (!NT_STATUS_IS_OK(status)) {
232 data_blob_free(&packet);
233 return;
234 }
235
236 if (msize < sizeof(*rec->header)) {
237 DEBUG(0,("messaging: bad message of size %d\n", (int)msize));
238 data_blob_free(&packet);
239 return;
240 }
241
242 rec = talloc(msg, struct messaging_rec);
243 if (rec == NULL) {
244 smb_panic("Unable to allocate messaging_rec");
245 }
246
247 talloc_steal(rec, packet.data);
248 rec->msg = msg;
249 rec->path = msg->path;
250 rec->header = (struct messaging_header *)packet.data;
251 rec->packet = packet;
252
253 if (msize != sizeof(*rec->header) + rec->header->length) {
254 DEBUG(0,("messaging: bad message header size %d should be %d\n",
255 rec->header->length, (int)(msize - sizeof(*rec->header))));
256 talloc_free(rec);
257 return;
258 }
259
260 messaging_dispatch(msg, rec);
261 talloc_free(rec);
262 }
263
264
265 /*
266 handle a socket event
267 */
messaging_handler(struct event_context * ev,struct fd_event * fde,uint16_t flags,void * private)268 static void messaging_handler(struct event_context *ev, struct fd_event *fde,
269 uint16_t flags, void *private)
270 {
271 struct messaging_context *msg = talloc_get_type(private,
272 struct messaging_context);
273 if (flags & EVENT_FD_WRITE) {
274 messaging_send_handler(msg);
275 }
276 if (flags & EVENT_FD_READ) {
277 messaging_recv_handler(msg);
278 }
279 }
280
281
282 /*
283 Register a dispatch function for a particular message type.
284 */
messaging_register(struct messaging_context * msg,void * private,uint32_t msg_type,msg_callback_t fn)285 NTSTATUS messaging_register(struct messaging_context *msg, void *private,
286 uint32_t msg_type, msg_callback_t fn)
287 {
288 struct dispatch_fn *d;
289
290 /* possibly expand dispatch array */
291 if (msg_type >= msg->num_types) {
292 struct dispatch_fn **dp;
293 int i;
294 dp = talloc_realloc(msg, msg->dispatch, struct dispatch_fn *, msg_type+1);
295 NT_STATUS_HAVE_NO_MEMORY(dp);
296 msg->dispatch = dp;
297 for (i=msg->num_types;i<=msg_type;i++) {
298 msg->dispatch[i] = NULL;
299 }
300 msg->num_types = msg_type+1;
301 }
302
303 d = talloc_zero(msg->dispatch, struct dispatch_fn);
304 NT_STATUS_HAVE_NO_MEMORY(d);
305 d->msg_type = msg_type;
306 d->private = private;
307 d->fn = fn;
308
309 DLIST_ADD(msg->dispatch[msg_type], d);
310
311 return NT_STATUS_OK;
312 }
313
314 /*
315 register a temporary message handler. The msg_type is allocated
316 above MSG_TMP_BASE
317 */
messaging_register_tmp(struct messaging_context * msg,void * private,msg_callback_t fn,uint32_t * msg_type)318 NTSTATUS messaging_register_tmp(struct messaging_context *msg, void *private,
319 msg_callback_t fn, uint32_t *msg_type)
320 {
321 struct dispatch_fn *d;
322 int id;
323
324 d = talloc_zero(msg->dispatch, struct dispatch_fn);
325 NT_STATUS_HAVE_NO_MEMORY(d);
326 d->private = private;
327 d->fn = fn;
328
329 id = idr_get_new_above(msg->dispatch_tree, d, MSG_TMP_BASE, UINT16_MAX);
330 if (id == -1) {
331 talloc_free(d);
332 return NT_STATUS_TOO_MANY_CONTEXT_IDS;
333 }
334
335 d->msg_type = (uint32_t)id;
336 (*msg_type) = d->msg_type;
337
338 return NT_STATUS_OK;
339 }
340
341 /*
342 De-register the function for a particular message type.
343 */
messaging_deregister(struct messaging_context * msg,uint32_t msg_type,void * private)344 void messaging_deregister(struct messaging_context *msg, uint32_t msg_type, void *private)
345 {
346 struct dispatch_fn *d, *next;
347
348 if (msg_type >= msg->num_types) {
349 d = idr_find(msg->dispatch_tree, msg_type);
350 if (!d) return;
351 idr_remove(msg->dispatch_tree, msg_type);
352 talloc_free(d);
353 return;
354 }
355
356 for (d = msg->dispatch[msg_type]; d; d = next) {
357 next = d->next;
358 if (d->private == private) {
359 DLIST_REMOVE(msg->dispatch[msg_type], d);
360 talloc_free(d);
361 }
362 }
363 }
364
365 /*
366 Send a message to a particular server
367 */
messaging_send(struct messaging_context * msg,uint32_t server,uint32_t msg_type,DATA_BLOB * data)368 NTSTATUS messaging_send(struct messaging_context *msg, uint32_t server,
369 uint32_t msg_type, DATA_BLOB *data)
370 {
371 struct messaging_rec *rec;
372 NTSTATUS status;
373 size_t dlength = data?data->length:0;
374
375 rec = talloc(msg, struct messaging_rec);
376 if (rec == NULL) {
377 return NT_STATUS_NO_MEMORY;
378 }
379
380 rec->packet = data_blob_talloc(rec, NULL, sizeof(*rec->header) + dlength);
381 if (rec->packet.data == NULL) {
382 talloc_free(rec);
383 return NT_STATUS_NO_MEMORY;
384 }
385
386 rec->msg = msg;
387 rec->header = (struct messaging_header *)rec->packet.data;
388 rec->header->version = MESSAGING_VERSION;
389 rec->header->msg_type = msg_type;
390 rec->header->from = msg->server_id;
391 rec->header->to = server;
392 rec->header->length = dlength;
393 if (dlength != 0) {
394 memcpy(rec->packet.data + sizeof(*rec->header),
395 data->data, dlength);
396 }
397
398 rec->path = messaging_path(msg, server);
399 talloc_steal(rec, rec->path);
400
401 if (msg->pending != NULL) {
402 status = STATUS_MORE_ENTRIES;
403 } else {
404 status = try_send(rec);
405 }
406
407 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
408 if (msg->pending == NULL) {
409 EVENT_FD_WRITEABLE(msg->event.fde);
410 }
411 DLIST_ADD_END(msg->pending, rec, struct messaging_rec *);
412 return NT_STATUS_OK;
413 }
414
415 talloc_free(rec);
416
417 return status;
418 }
419
420 /*
421 Send a message to a particular server, with the message containing a single pointer
422 */
messaging_send_ptr(struct messaging_context * msg,uint32_t server,uint32_t msg_type,void * ptr)423 NTSTATUS messaging_send_ptr(struct messaging_context *msg, uint32_t server,
424 uint32_t msg_type, void *ptr)
425 {
426 DATA_BLOB blob;
427
428 blob.data = (void *)&ptr;
429 blob.length = sizeof(void *);
430
431 return messaging_send(msg, server, msg_type, &blob);
432 }
433
434
435 /*
436 destroy the messaging context
437 */
messaging_destructor(struct messaging_context * msg)438 static int messaging_destructor(struct messaging_context *msg)
439 {
440 unlink(msg->path);
441 while (msg->names && msg->names[0]) {
442 irpc_remove_name(msg, msg->names[0]);
443 }
444 return 0;
445 }
446
447 /*
448 create the listening socket and setup the dispatcher
449 */
messaging_init(TALLOC_CTX * mem_ctx,uint32_t server_id,struct event_context * ev)450 struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, uint32_t server_id,
451 struct event_context *ev)
452 {
453 struct messaging_context *msg;
454 NTSTATUS status;
455 struct socket_address *path;
456 char *dir;
457
458 msg = talloc_zero(mem_ctx, struct messaging_context);
459 if (msg == NULL) {
460 return NULL;
461 }
462
463 if (ev == NULL) {
464 ev = event_context_init(msg);
465 }
466
467 /* create the messaging directory if needed */
468 dir = smbd_tmp_path(msg, "messaging");
469 mkdir(dir, 0700);
470 talloc_free(dir);
471
472 msg->base_path = smbd_tmp_path(msg, "messaging");
473 msg->path = messaging_path(msg, server_id);
474 msg->server_id = server_id;
475 msg->idr = idr_init(msg);
476 msg->dispatch_tree = idr_init(msg);
477 msg->start_time = timeval_current();
478
479 status = socket_create("unix", SOCKET_TYPE_DGRAM, &msg->sock, 0);
480 if (!NT_STATUS_IS_OK(status)) {
481 talloc_free(msg);
482 return NULL;
483 }
484
485 /* by stealing here we ensure that the socket is cleaned up (and even
486 deleted) on exit */
487 talloc_steal(msg, msg->sock);
488
489 path = socket_address_from_strings(msg, msg->sock->backend_name,
490 msg->path, 0);
491 if (!path) {
492 talloc_free(msg);
493 return NULL;
494 }
495
496 status = socket_listen(msg->sock, path, 50, 0);
497 if (!NT_STATUS_IS_OK(status)) {
498 DEBUG(0,("Unable to setup messaging listener for '%s':%s\n", msg->path, nt_errstr(status)));
499 talloc_free(msg);
500 return NULL;
501 }
502
503 /* it needs to be non blocking for sends */
504 set_blocking(socket_get_fd(msg->sock), False);
505
506 msg->event.ev = talloc_reference(msg, ev);
507 msg->event.fde = event_add_fd(ev, msg, socket_get_fd(msg->sock),
508 EVENT_FD_READ, messaging_handler, msg);
509
510 talloc_set_destructor(msg, messaging_destructor);
511
512 messaging_register(msg, NULL, MSG_PING, ping_message);
513 messaging_register(msg, NULL, MSG_IRPC, irpc_handler);
514 IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
515
516 return msg;
517 }
518
519 /*
520 A hack, for the short term until we get 'client only' messaging in place
521 */
messaging_client_init(TALLOC_CTX * mem_ctx,struct event_context * ev)522 struct messaging_context *messaging_client_init(TALLOC_CTX *mem_ctx,
523 struct event_context *ev)
524 {
525 return messaging_init(mem_ctx, random() % 0x10000000, ev);
526 }
527 /*
528 a list of registered irpc server functions
529 */
530 struct irpc_list {
531 struct irpc_list *next, *prev;
532 struct GUID uuid;
533 const struct dcerpc_interface_table *table;
534 int callnum;
535 irpc_function_t fn;
536 void *private;
537 };
538
539
540 /*
541 register a irpc server function
542 */
irpc_register(struct messaging_context * msg_ctx,const struct dcerpc_interface_table * table,int callnum,irpc_function_t fn,void * private)543 NTSTATUS irpc_register(struct messaging_context *msg_ctx,
544 const struct dcerpc_interface_table *table,
545 int callnum, irpc_function_t fn, void *private)
546 {
547 struct irpc_list *irpc;
548
549 /* override an existing handler, if any */
550 for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
551 if (irpc->table == table && irpc->callnum == callnum) {
552 break;
553 }
554 }
555 if (irpc == NULL) {
556 irpc = talloc(msg_ctx, struct irpc_list);
557 NT_STATUS_HAVE_NO_MEMORY(irpc);
558 DLIST_ADD(msg_ctx->irpc, irpc);
559 }
560
561 irpc->table = table;
562 irpc->callnum = callnum;
563 irpc->fn = fn;
564 irpc->private = private;
565 irpc->uuid = irpc->table->syntax_id.uuid;
566
567 return NT_STATUS_OK;
568 }
569
570
571 /*
572 handle an incoming irpc reply message
573 */
irpc_handler_reply(struct messaging_context * msg_ctx,struct irpc_message * m)574 static void irpc_handler_reply(struct messaging_context *msg_ctx, struct irpc_message *m)
575 {
576 struct irpc_request *irpc;
577
578 irpc = idr_find(msg_ctx->idr, m->header.callid);
579 if (irpc == NULL) return;
580
581 /* parse the reply data */
582 irpc->status = irpc->table->calls[irpc->callnum].ndr_pull(m->ndr, NDR_OUT, irpc->r);
583 if (NT_STATUS_IS_OK(irpc->status)) {
584 irpc->status = m->header.status;
585 talloc_steal(irpc->mem_ctx, m);
586 } else {
587 talloc_steal(irpc, m);
588 }
589 irpc->done = True;
590 if (irpc->async.fn) {
591 irpc->async.fn(irpc);
592 }
593 }
594
595 /*
596 send a irpc reply
597 */
irpc_send_reply(struct irpc_message * m,NTSTATUS status)598 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
599 {
600 struct ndr_push *push;
601 DATA_BLOB packet;
602
603 m->header.status = status;
604
605 /* setup the reply */
606 push = ndr_push_init_ctx(m->ndr);
607 if (push == NULL) {
608 status = NT_STATUS_NO_MEMORY;
609 goto failed;
610 }
611
612 m->header.flags |= IRPC_FLAG_REPLY;
613
614 /* construct the packet */
615 status = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
616 if (!NT_STATUS_IS_OK(status)) goto failed;
617
618 status = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
619 if (!NT_STATUS_IS_OK(status)) goto failed;
620
621 /* send the reply message */
622 packet = ndr_push_blob(push);
623 status = messaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
624 if (!NT_STATUS_IS_OK(status)) goto failed;
625
626 failed:
627 talloc_free(m);
628 return status;
629 }
630
631 /*
632 handle an incoming irpc request message
633 */
irpc_handler_request(struct messaging_context * msg_ctx,struct irpc_message * m)634 static void irpc_handler_request(struct messaging_context *msg_ctx,
635 struct irpc_message *m)
636 {
637 struct irpc_list *i;
638 void *r;
639 NTSTATUS status;
640
641 for (i=msg_ctx->irpc; i; i=i->next) {
642 if (GUID_equal(&i->uuid, &m->header.uuid) &&
643 i->table->syntax_id.if_version == m->header.if_version &&
644 i->callnum == m->header.callnum) {
645 break;
646 }
647 }
648
649 if (i == NULL) {
650 /* no registered handler for this message */
651 talloc_free(m);
652 return;
653 }
654
655 /* allocate space for the structure */
656 r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
657 if (r == NULL) goto failed;
658
659 /* parse the request data */
660 status = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
661 if (!NT_STATUS_IS_OK(status)) goto failed;
662
663 /* make the call */
664 m->private = i->private;
665 m->defer_reply = False;
666 m->msg_ctx = msg_ctx;
667 m->irpc = i;
668 m->data = r;
669 m->ev = msg_ctx->event.ev;
670
671 m->header.status = i->fn(m, r);
672
673 if (m->defer_reply) {
674 /* the server function has asked to defer the reply to later */
675 talloc_steal(msg_ctx, m);
676 return;
677 }
678
679 irpc_send_reply(m, m->header.status);
680 return;
681
682 failed:
683 talloc_free(m);
684 }
685
686 /*
687 handle an incoming irpc message
688 */
irpc_handler(struct messaging_context * msg_ctx,void * private,uint32_t msg_type,uint32_t src,DATA_BLOB * packet)689 static void irpc_handler(struct messaging_context *msg_ctx, void *private,
690 uint32_t msg_type, uint32_t src, DATA_BLOB *packet)
691 {
692 struct irpc_message *m;
693 NTSTATUS status;
694
695 m = talloc(msg_ctx, struct irpc_message);
696 if (m == NULL) goto failed;
697
698 m->from = src;
699
700 m->ndr = ndr_pull_init_blob(packet, m);
701 if (m->ndr == NULL) goto failed;
702
703 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
704
705 status = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
706 if (!NT_STATUS_IS_OK(status)) goto failed;
707
708 if (m->header.flags & IRPC_FLAG_REPLY) {
709 irpc_handler_reply(msg_ctx, m);
710 } else {
711 irpc_handler_request(msg_ctx, m);
712 }
713 return;
714
715 failed:
716 talloc_free(m);
717 }
718
719
720 /*
721 destroy a irpc request
722 */
irpc_destructor(struct irpc_request * irpc)723 static int irpc_destructor(struct irpc_request *irpc)
724 {
725 idr_remove(irpc->msg_ctx->idr, irpc->callid);
726 return 0;
727 }
728
729 /*
730 timeout a irpc request
731 */
irpc_timeout(struct event_context * ev,struct timed_event * te,struct timeval t,void * private)732 static void irpc_timeout(struct event_context *ev, struct timed_event *te,
733 struct timeval t, void *private)
734 {
735 struct irpc_request *irpc = talloc_get_type(private, struct irpc_request);
736 irpc->status = NT_STATUS_IO_TIMEOUT;
737 irpc->done = True;
738 if (irpc->async.fn) {
739 irpc->async.fn(irpc);
740 }
741 }
742
743
744 /*
745 make a irpc call - async send
746 */
irpc_call_send(struct messaging_context * msg_ctx,uint32_t server_id,const struct dcerpc_interface_table * table,int callnum,void * r,TALLOC_CTX * ctx)747 struct irpc_request *irpc_call_send(struct messaging_context *msg_ctx,
748 uint32_t server_id,
749 const struct dcerpc_interface_table *table,
750 int callnum, void *r, TALLOC_CTX *ctx)
751 {
752 struct irpc_header header;
753 struct ndr_push *ndr;
754 NTSTATUS status;
755 DATA_BLOB packet;
756 struct irpc_request *irpc;
757
758 irpc = talloc(msg_ctx, struct irpc_request);
759 if (irpc == NULL) goto failed;
760
761 irpc->msg_ctx = msg_ctx;
762 irpc->table = table;
763 irpc->callnum = callnum;
764 irpc->callid = idr_get_new(msg_ctx->idr, irpc, UINT16_MAX);
765 if (irpc->callid == -1) goto failed;
766 irpc->r = r;
767 irpc->done = False;
768 irpc->async.fn = NULL;
769 irpc->mem_ctx = ctx;
770
771 talloc_set_destructor(irpc, irpc_destructor);
772
773 /* setup the header */
774 header.uuid = table->syntax_id.uuid;
775
776 header.if_version = table->syntax_id.if_version;
777 header.callid = irpc->callid;
778 header.callnum = callnum;
779 header.flags = 0;
780 header.status = NT_STATUS_OK;
781
782 /* construct the irpc packet */
783 ndr = ndr_push_init_ctx(irpc);
784 if (ndr == NULL) goto failed;
785
786 status = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
787 if (!NT_STATUS_IS_OK(status)) goto failed;
788
789 status = table->calls[callnum].ndr_push(ndr, NDR_IN, r);
790 if (!NT_STATUS_IS_OK(status)) goto failed;
791
792 /* and send it */
793 packet = ndr_push_blob(ndr);
794 status = messaging_send(msg_ctx, server_id, MSG_IRPC, &packet);
795 if (!NT_STATUS_IS_OK(status)) goto failed;
796
797 event_add_timed(msg_ctx->event.ev, irpc,
798 timeval_current_ofs(IRPC_CALL_TIMEOUT, 0),
799 irpc_timeout, irpc);
800
801 talloc_free(ndr);
802 return irpc;
803
804 failed:
805 talloc_free(irpc);
806 return NULL;
807 }
808
809 /*
810 wait for a irpc reply
811 */
irpc_call_recv(struct irpc_request * irpc)812 NTSTATUS irpc_call_recv(struct irpc_request *irpc)
813 {
814 NTSTATUS status;
815
816 NT_STATUS_HAVE_NO_MEMORY(irpc);
817
818 while (!irpc->done) {
819 if (event_loop_once(irpc->msg_ctx->event.ev) != 0) {
820 return NT_STATUS_CONNECTION_DISCONNECTED;
821 }
822 }
823 status = irpc->status;
824 talloc_free(irpc);
825 return status;
826 }
827
828 /*
829 perform a synchronous irpc request
830 */
irpc_call(struct messaging_context * msg_ctx,uint32_t server_id,const struct dcerpc_interface_table * table,int callnum,void * r,TALLOC_CTX * mem_ctx)831 NTSTATUS irpc_call(struct messaging_context *msg_ctx,
832 uint32_t server_id,
833 const struct dcerpc_interface_table *table,
834 int callnum, void *r,
835 TALLOC_CTX *mem_ctx)
836 {
837 struct irpc_request *irpc = irpc_call_send(msg_ctx, server_id,
838 table, callnum, r, mem_ctx);
839 return irpc_call_recv(irpc);
840 }
841
842 /*
843 open the naming database
844 */
irpc_namedb_open(struct messaging_context * msg_ctx)845 static struct tdb_wrap *irpc_namedb_open(struct messaging_context *msg_ctx)
846 {
847 struct tdb_wrap *t;
848 char *path = talloc_asprintf(msg_ctx, "%s/names.tdb", msg_ctx->base_path);
849 if (path == NULL) {
850 return NULL;
851 }
852 t = tdb_wrap_open(msg_ctx, path, 0, 0, O_RDWR|O_CREAT, 0660);
853 talloc_free(path);
854 return t;
855 }
856
857
858 /*
859 add a string name that this irpc server can be called on
860 */
irpc_add_name(struct messaging_context * msg_ctx,const char * name)861 NTSTATUS irpc_add_name(struct messaging_context *msg_ctx, const char *name)
862 {
863 struct tdb_wrap *t;
864 TDB_DATA rec;
865 int count;
866 NTSTATUS status = NT_STATUS_OK;
867
868 t = irpc_namedb_open(msg_ctx);
869 NT_STATUS_HAVE_NO_MEMORY(t);
870
871 if (tdb_lock_bystring(t->tdb, name) != 0) {
872 talloc_free(t);
873 return NT_STATUS_LOCK_NOT_GRANTED;
874 }
875 rec = tdb_fetch_bystring(t->tdb, name);
876 count = rec.dsize / sizeof(uint32_t);
877 rec.dptr = (unsigned char *)realloc_p(rec.dptr, uint32_t, count+1);
878 rec.dsize += sizeof(uint32_t);
879 if (rec.dptr == NULL) {
880 tdb_unlock_bystring(t->tdb, name);
881 talloc_free(t);
882 return NT_STATUS_NO_MEMORY;
883 }
884 ((uint32_t *)rec.dptr)[count] = msg_ctx->server_id;
885 if (tdb_store_bystring(t->tdb, name, rec, 0) != 0) {
886 status = NT_STATUS_INTERNAL_ERROR;
887 }
888 free(rec.dptr);
889 tdb_unlock_bystring(t->tdb, name);
890 talloc_free(t);
891
892 msg_ctx->names = str_list_add(msg_ctx->names, name);
893 talloc_steal(msg_ctx, msg_ctx->names);
894
895 return status;
896 }
897
898 /*
899 return a list of server ids for a server name
900 */
irpc_servers_byname(struct messaging_context * msg_ctx,const char * name)901 uint32_t *irpc_servers_byname(struct messaging_context *msg_ctx, const char *name)
902 {
903 struct tdb_wrap *t;
904 TDB_DATA rec;
905 int count, i;
906 uint32_t *ret;
907
908 t = irpc_namedb_open(msg_ctx);
909 if (t == NULL) {
910 return NULL;
911 }
912
913 if (tdb_lock_bystring(t->tdb, name) != 0) {
914 talloc_free(t);
915 return NULL;
916 }
917 rec = tdb_fetch_bystring(t->tdb, name);
918 if (rec.dptr == NULL) {
919 tdb_unlock_bystring(t->tdb, name);
920 talloc_free(t);
921 return NULL;
922 }
923 count = rec.dsize / sizeof(uint32_t);
924 ret = talloc_array(msg_ctx, uint32_t, count+1);
925 if (ret == NULL) {
926 tdb_unlock_bystring(t->tdb, name);
927 talloc_free(t);
928 return NULL;
929 }
930 for (i=0;i<count;i++) {
931 ret[i] = ((uint32_t *)rec.dptr)[i];
932 }
933 ret[i] = 0;
934 free(rec.dptr);
935 tdb_unlock_bystring(t->tdb, name);
936 talloc_free(t);
937
938 return ret;
939 }
940
941 /*
942 remove a name from a messaging context
943 */
irpc_remove_name(struct messaging_context * msg_ctx,const char * name)944 void irpc_remove_name(struct messaging_context *msg_ctx, const char *name)
945 {
946 struct tdb_wrap *t;
947 TDB_DATA rec;
948 int count, i;
949 uint32_t *ids;
950
951 str_list_remove(msg_ctx->names, name);
952
953 t = irpc_namedb_open(msg_ctx);
954 if (t == NULL) {
955 return;
956 }
957
958 if (tdb_lock_bystring(t->tdb, name) != 0) {
959 talloc_free(t);
960 return;
961 }
962 rec = tdb_fetch_bystring(t->tdb, name);
963 count = rec.dsize / sizeof(uint32_t);
964 if (count == 0) {
965 tdb_unlock_bystring(t->tdb, name);
966 talloc_free(t);
967 return;
968 }
969 ids = (uint32_t *)rec.dptr;
970 for (i=0;i<count;i++) {
971 if (ids[i] == msg_ctx->server_id) {
972 if (i < count-1) {
973 memmove(ids+i, ids+i+1, count-(i+1));
974 }
975 rec.dsize -= sizeof(uint32_t);
976 break;
977 }
978 }
979 tdb_store_bystring(t->tdb, name, rec, 0);
980 free(rec.dptr);
981 tdb_unlock_bystring(t->tdb, name);
982 talloc_free(t);
983 }
984