/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- messaging_tdb_signal_handler
- messaging_tdb_init
- message_key_pid
- messaging_tdb_fetch
- messaging_tdb_store
- message_notify
- messaging_tdb_send
- retrieve_all_messages
- message_dispatch
1 /*
2 Unix SMB/CIFS implementation.
3 Samba internal messaging functions
4 Copyright (C) 2007 by Volker Lendecke
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /**
21 @defgroup messages Internal messaging framework
22 @{
23 @file messages.c
24
25 @brief Module for internal messaging between Samba daemons.
26
27 The idea is that if a part of Samba wants to do communication with
28 another Samba process then it will do a message_register() of a
29 dispatch function, and use message_send_pid() to send messages to
30 that process.
31
32 The dispatch function is given the pid of the sender, and it can
33 use that to reply by message_send_pid(). See ping_message() for a
34 simple example.
35
36 @caution Dispatch functions must be able to cope with incoming
37 messages on an *odd* byte boundary.
38
39 This system doesn't have any inherent size limitations but is not
40 very efficient for large messages or when messages are sent in very
41 quick succession.
42
43 */
44
45 #include "includes.h"
46 #include "librpc/gen_ndr/messaging.h"
47 #include "librpc/gen_ndr/ndr_messaging.h"
48
49 struct messaging_tdb_context {
50 struct messaging_context *msg_ctx;
51 struct tdb_wrap *tdb;
52 struct tevent_signal *se;
53 int received_messages;
54 };
55
56 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
57 struct server_id pid, int msg_type,
58 const DATA_BLOB *data,
59 struct messaging_backend *backend);
60 static void message_dispatch(struct messaging_context *msg_ctx);
61
62 static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
/* [<][>][^][v][top][bottom][index][help] */
63 struct tevent_signal *se,
64 int signum, int count,
65 void *_info, void *private_data)
66 {
67 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
68 struct messaging_tdb_context);
69
70 ctx->received_messages++;
71
72 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
73 signum, count, ctx->received_messages));
74
75 message_dispatch(ctx->msg_ctx);
76 }
77
78 /****************************************************************************
79 Initialise the messaging functions.
80 ****************************************************************************/
81
82 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
/* [<][>][^][v][top][bottom][index][help] */
83 TALLOC_CTX *mem_ctx,
84 struct messaging_backend **presult)
85 {
86 struct messaging_backend *result;
87 struct messaging_tdb_context *ctx;
88
89 if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
90 DEBUG(0, ("talloc failed\n"));
91 return NT_STATUS_NO_MEMORY;
92 }
93
94 ctx = TALLOC_ZERO_P(result, struct messaging_tdb_context);
95 if (!ctx) {
96 DEBUG(0, ("talloc failed\n"));
97 TALLOC_FREE(result);
98 return NT_STATUS_NO_MEMORY;
99 }
100 result->private_data = ctx;
101 result->send_fn = messaging_tdb_send;
102
103 ctx->msg_ctx = msg_ctx;
104
105 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"),
106 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
107 O_RDWR|O_CREAT,0600);
108
109 if (!ctx->tdb) {
110 NTSTATUS status = map_nt_error_from_unix(errno);
111 DEBUG(0, ("ERROR: Failed to initialise messages database: "
112 "%s\n", strerror(errno)));
113 TALLOC_FREE(result);
114 return status;
115 }
116
117 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
118 ctx,
119 SIGUSR1, 0,
120 messaging_tdb_signal_handler,
121 ctx);
122 if (!ctx->se) {
123 NTSTATUS status = map_nt_error_from_unix(errno);
124 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
125 "%s\n", strerror(errno)));
126 TALLOC_FREE(result);
127 return status;
128 }
129
130 sec_init();
131
132 /* Activate the per-hashchain freelist */
133 tdb_set_max_dead(ctx->tdb->tdb, 5);
134
135 *presult = result;
136 return NT_STATUS_OK;
137 }
138
139 /*******************************************************************
140 Form a static tdb key from a pid.
141 ******************************************************************/
142
143 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
/* [<][>][^][v][top][bottom][index][help] */
144 {
145 char *key;
146 TDB_DATA kbuf;
147
148 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
149
150 SMB_ASSERT(key != NULL);
151
152 kbuf.dptr = (uint8 *)key;
153 kbuf.dsize = strlen(key)+1;
154 return kbuf;
155 }
156
157 /*
158 Fetch the messaging array for a process
159 */
160
161 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
/* [<][>][^][v][top][bottom][index][help] */
162 TDB_DATA key,
163 TALLOC_CTX *mem_ctx,
164 struct messaging_array **presult)
165 {
166 struct messaging_array *result;
167 TDB_DATA data;
168 DATA_BLOB blob;
169 enum ndr_err_code ndr_err;
170
171 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
172 return NT_STATUS_NO_MEMORY;
173 }
174
175 data = tdb_fetch(msg_tdb, key);
176
177 if (data.dptr == NULL) {
178 *presult = result;
179 return NT_STATUS_OK;
180 }
181
182 blob = data_blob_const(data.dptr, data.dsize);
183
184 ndr_err = ndr_pull_struct_blob(
185 &blob, result, NULL, result,
186 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
187
188 SAFE_FREE(data.dptr);
189
190 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
191 TALLOC_FREE(result);
192 return ndr_map_error2ntstatus(ndr_err);
193 }
194
195 if (DEBUGLEVEL >= 10) {
196 DEBUG(10, ("messaging_tdb_fetch:\n"));
197 NDR_PRINT_DEBUG(messaging_array, result);
198 }
199
200 *presult = result;
201 return NT_STATUS_OK;
202 }
203
204 /*
205 Store a messaging array for a pid
206 */
207
208 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
/* [<][>][^][v][top][bottom][index][help] */
209 TDB_DATA key,
210 struct messaging_array *array)
211 {
212 TDB_DATA data;
213 DATA_BLOB blob;
214 enum ndr_err_code ndr_err;
215 TALLOC_CTX *mem_ctx;
216 int ret;
217
218 if (array->num_messages == 0) {
219 tdb_delete(msg_tdb, key);
220 return NT_STATUS_OK;
221 }
222
223 if (!(mem_ctx = talloc_new(array))) {
224 return NT_STATUS_NO_MEMORY;
225 }
226
227 ndr_err = ndr_push_struct_blob(
228 &blob, mem_ctx, NULL, array,
229 (ndr_push_flags_fn_t)ndr_push_messaging_array);
230
231 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232 talloc_free(mem_ctx);
233 return ndr_map_error2ntstatus(ndr_err);
234 }
235
236 if (DEBUGLEVEL >= 10) {
237 DEBUG(10, ("messaging_tdb_store:\n"));
238 NDR_PRINT_DEBUG(messaging_array, array);
239 }
240
241 data.dptr = blob.data;
242 data.dsize = blob.length;
243
244 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
245 TALLOC_FREE(mem_ctx);
246
247 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
248 }
249
250 /****************************************************************************
251 Notify a process that it has a message. If the process doesn't exist
252 then delete its record in the database.
253 ****************************************************************************/
254
255 static NTSTATUS message_notify(struct server_id procid)
/* [<][>][^][v][top][bottom][index][help] */
256 {
257 pid_t pid = procid.pid;
258 int ret;
259 uid_t euid = geteuid();
260
261 /*
262 * Doing kill with a non-positive pid causes messages to be
263 * sent to places we don't want.
264 */
265
266 SMB_ASSERT(pid > 0);
267
268 if (euid != 0) {
269 /* If we're not root become so to send the message. */
270 save_re_uid();
271 set_effective_uid(0);
272 }
273
274 ret = kill(pid, SIGUSR1);
275
276 if (euid != 0) {
277 /* Go back to who we were. */
278 int saved_errno = errno;
279 restore_re_uid_fromroot();
280 errno = saved_errno;
281 }
282
283 if (ret == 0) {
284 return NT_STATUS_OK;
285 }
286
287 /*
288 * Something has gone wrong
289 */
290
291 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
292 strerror(errno)));
293
294 /*
295 * No call to map_nt_error_from_unix -- don't want to link in
296 * errormap.o into lots of utils.
297 */
298
299 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
300 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
301 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
302 return NT_STATUS_UNSUCCESSFUL;
303 }
304
305 /****************************************************************************
306 Send a message to a particular pid.
307 ****************************************************************************/
308
309 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
/* [<][>][^][v][top][bottom][index][help] */
310 struct server_id pid, int msg_type,
311 const DATA_BLOB *data,
312 struct messaging_backend *backend)
313 {
314 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
315 struct messaging_tdb_context);
316 struct messaging_array *msg_array;
317 struct messaging_rec *rec;
318 NTSTATUS status;
319 TDB_DATA key;
320 struct tdb_wrap *tdb = ctx->tdb;
321 TALLOC_CTX *frame = talloc_stackframe();
322
323 /* NULL pointer means implicit length zero. */
324 if (!data->data) {
325 SMB_ASSERT(data->length == 0);
326 }
327
328 /*
329 * Doing kill with a non-positive pid causes messages to be
330 * sent to places we don't want.
331 */
332
333 SMB_ASSERT(procid_to_pid(&pid) > 0);
334
335 key = message_key_pid(frame, pid);
336
337 if (tdb_chainlock(tdb->tdb, key) == -1) {
338 TALLOC_FREE(frame);
339 return NT_STATUS_LOCK_NOT_GRANTED;
340 }
341
342 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
343
344 if (!NT_STATUS_IS_OK(status)) {
345 goto done;
346 }
347
348 if ((msg_type & MSG_FLAG_LOWPRIORITY)
349 && (msg_array->num_messages > 1000)) {
350 DEBUG(5, ("Dropping message for PID %s\n",
351 procid_str_static(&pid)));
352 status = NT_STATUS_INSUFFICIENT_RESOURCES;
353 goto done;
354 }
355
356 if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages,
357 struct messaging_rec,
358 msg_array->num_messages+1))) {
359 status = NT_STATUS_NO_MEMORY;
360 goto done;
361 }
362
363 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
364 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
365 rec[msg_array->num_messages].dest = pid;
366 rec[msg_array->num_messages].src = procid_self();
367 rec[msg_array->num_messages].buf = *data;
368
369 msg_array->messages = rec;
370 msg_array->num_messages += 1;
371
372 status = messaging_tdb_store(tdb->tdb, key, msg_array);
373
374 if (!NT_STATUS_IS_OK(status)) {
375 goto done;
376 }
377
378 status = message_notify(pid);
379
380 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
381 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
382 procid_str_static(&pid)));
383 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
384 }
385
386 done:
387 tdb_chainunlock(tdb->tdb, key);
388 TALLOC_FREE(frame);
389 return status;
390 }
391
392 /****************************************************************************
393 Retrieve all messages for the current process.
394 ****************************************************************************/
395
396 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
/* [<][>][^][v][top][bottom][index][help] */
397 TALLOC_CTX *mem_ctx,
398 struct messaging_array **presult)
399 {
400 struct messaging_array *result;
401 TDB_DATA key = message_key_pid(mem_ctx, procid_self());
402 NTSTATUS status;
403
404 if (tdb_chainlock(msg_tdb, key) == -1) {
405 TALLOC_FREE(key.dptr);
406 return NT_STATUS_LOCK_NOT_GRANTED;
407 }
408
409 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
410
411 /*
412 * We delete the record here, tdb_set_max_dead keeps it around
413 */
414 tdb_delete(msg_tdb, key);
415 tdb_chainunlock(msg_tdb, key);
416
417 if (NT_STATUS_IS_OK(status)) {
418 *presult = result;
419 }
420
421 TALLOC_FREE(key.dptr);
422
423 return status;
424 }
425
426 /****************************************************************************
427 Receive and dispatch any messages pending for this process.
428 JRA changed Dec 13 2006. Only one message handler now permitted per type.
429 *NOTE*: Dispatch functions must be able to cope with incoming
430 messages on an *odd* byte boundary.
431 ****************************************************************************/
432
433 static void message_dispatch(struct messaging_context *msg_ctx)
/* [<][>][^][v][top][bottom][index][help] */
434 {
435 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
436 struct messaging_tdb_context);
437 struct messaging_array *msg_array = NULL;
438 struct tdb_wrap *tdb = ctx->tdb;
439 NTSTATUS status;
440 uint32 i;
441
442 if (ctx->received_messages == 0) {
443 return;
444 }
445
446 DEBUG(10, ("message_dispatch: received_messages = %d\n",
447 ctx->received_messages));
448
449 status = retrieve_all_messages(tdb->tdb, NULL, &msg_array);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
452 nt_errstr(status)));
453 return;
454 }
455
456 ctx->received_messages = 0;
457
458 for (i=0; i<msg_array->num_messages; i++) {
459 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
460 }
461
462 TALLOC_FREE(msg_array);
463 }
464
465 /** @} **/