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