source: vendor/3.6.23/source3/lib/messages_local.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 12.9 KB
Line 
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 "system/filesys.h"
47#include "messages.h"
48#include "lib/util/tdb_wrap.h"
49
50struct messaging_tdb_context {
51 struct messaging_context *msg_ctx;
52 struct tdb_wrap *tdb;
53 struct tevent_signal *se;
54 int received_messages;
55};
56
57static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
58 struct server_id pid, int msg_type,
59 const DATA_BLOB *data,
60 struct messaging_backend *backend);
61static void message_dispatch(struct messaging_context *msg_ctx);
62
63static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
64 struct tevent_signal *se,
65 int signum, int count,
66 void *_info, void *private_data)
67{
68 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
69 struct messaging_tdb_context);
70
71 ctx->received_messages++;
72
73 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
74 signum, count, ctx->received_messages));
75
76 message_dispatch(ctx->msg_ctx);
77}
78
79/****************************************************************************
80 Initialise the messaging functions.
81****************************************************************************/
82
83NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
84 TALLOC_CTX *mem_ctx,
85 struct messaging_backend **presult)
86{
87 struct messaging_backend *result;
88 struct messaging_tdb_context *ctx;
89
90 if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
91 DEBUG(0, ("talloc failed\n"));
92 return NT_STATUS_NO_MEMORY;
93 }
94
95 ctx = TALLOC_ZERO_P(result, struct messaging_tdb_context);
96 if (!ctx) {
97 DEBUG(0, ("talloc failed\n"));
98 TALLOC_FREE(result);
99 return NT_STATUS_NO_MEMORY;
100 }
101 result->private_data = ctx;
102 result->send_fn = messaging_tdb_send;
103
104 ctx->msg_ctx = msg_ctx;
105
106 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"), 0,
107 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
108 O_RDWR|O_CREAT,0600);
109
110 if (!ctx->tdb) {
111 NTSTATUS status = map_nt_error_from_unix(errno);
112 DEBUG(2, ("ERROR: Failed to initialise messages database: "
113 "%s\n", strerror(errno)));
114 TALLOC_FREE(result);
115 return status;
116 }
117
118 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
119 ctx,
120 SIGUSR1, 0,
121 messaging_tdb_signal_handler,
122 ctx);
123 if (!ctx->se) {
124 NTSTATUS status = map_nt_error_from_unix(errno);
125 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
126 "%s\n", strerror(errno)));
127 TALLOC_FREE(result);
128 return status;
129 }
130
131 sec_init();
132
133 *presult = result;
134 return NT_STATUS_OK;
135}
136
137bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
138{
139 struct tdb_wrap *db;
140
141 /*
142 * Open the tdb in the parent process (smbd) so that our
143 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
144 * work.
145 */
146
147 db = tdb_wrap_open(mem_ctx, lock_path("messages.tdb"), 0,
148 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
149 O_RDWR|O_CREAT,0600);
150 if (db == NULL) {
151 DEBUG(1, ("could not open messaging.tdb: %s\n",
152 strerror(errno)));
153 return false;
154 }
155 return true;
156}
157
158/*******************************************************************
159 Form a static tdb key from a pid.
160******************************************************************/
161
162static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
163{
164 char *key;
165 TDB_DATA kbuf;
166
167 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
168
169 SMB_ASSERT(key != NULL);
170
171 kbuf.dptr = (uint8 *)key;
172 kbuf.dsize = strlen(key)+1;
173 return kbuf;
174}
175
176/*
177 Fetch the messaging array for a process
178 */
179
180static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
181 TDB_DATA key,
182 TALLOC_CTX *mem_ctx,
183 struct messaging_array **presult)
184{
185 struct messaging_array *result;
186 TDB_DATA data;
187 DATA_BLOB blob;
188 enum ndr_err_code ndr_err;
189
190 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
191 return NT_STATUS_NO_MEMORY;
192 }
193
194 data = tdb_fetch(msg_tdb, key);
195
196 if (data.dptr == NULL) {
197 *presult = result;
198 return NT_STATUS_OK;
199 }
200
201 blob = data_blob_const(data.dptr, data.dsize);
202
203 ndr_err = ndr_pull_struct_blob(
204 &blob, result, result,
205 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
206
207 SAFE_FREE(data.dptr);
208
209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
210 TALLOC_FREE(result);
211 return ndr_map_error2ntstatus(ndr_err);
212 }
213
214 if (DEBUGLEVEL >= 10) {
215 DEBUG(10, ("messaging_tdb_fetch:\n"));
216 NDR_PRINT_DEBUG(messaging_array, result);
217 }
218
219 *presult = result;
220 return NT_STATUS_OK;
221}
222
223/*
224 Store a messaging array for a pid
225*/
226
227static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
228 TDB_DATA key,
229 struct messaging_array *array)
230{
231 TDB_DATA data;
232 DATA_BLOB blob;
233 enum ndr_err_code ndr_err;
234 TALLOC_CTX *mem_ctx;
235 int ret;
236
237 if (array->num_messages == 0) {
238 tdb_delete(msg_tdb, key);
239 return NT_STATUS_OK;
240 }
241
242 if (!(mem_ctx = talloc_new(array))) {
243 return NT_STATUS_NO_MEMORY;
244 }
245
246 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
247 (ndr_push_flags_fn_t)ndr_push_messaging_array);
248
249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
250 talloc_free(mem_ctx);
251 return ndr_map_error2ntstatus(ndr_err);
252 }
253
254 if (DEBUGLEVEL >= 10) {
255 DEBUG(10, ("messaging_tdb_store:\n"));
256 NDR_PRINT_DEBUG(messaging_array, array);
257 }
258
259 data.dptr = blob.data;
260 data.dsize = blob.length;
261
262 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
263 TALLOC_FREE(mem_ctx);
264
265 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
266}
267
268/****************************************************************************
269 Notify a process that it has a message. If the process doesn't exist
270 then delete its record in the database.
271****************************************************************************/
272
273static NTSTATUS message_notify(struct server_id procid)
274{
275 pid_t pid = procid.pid;
276 int ret;
277 uid_t euid = geteuid();
278
279 /*
280 * Doing kill with a non-positive pid causes messages to be
281 * sent to places we don't want.
282 */
283
284 SMB_ASSERT(pid > 0);
285
286 if (euid != 0) {
287 /* If we're not root become so to send the message. */
288 save_re_uid();
289 set_effective_uid(0);
290 }
291
292 ret = kill(pid, SIGUSR1);
293
294 if (euid != 0) {
295 /* Go back to who we were. */
296 int saved_errno = errno;
297 restore_re_uid_fromroot();
298 errno = saved_errno;
299 }
300
301 if (ret == 0) {
302 return NT_STATUS_OK;
303 }
304
305 /*
306 * Something has gone wrong
307 */
308
309 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
310 strerror(errno)));
311
312 /*
313 * No call to map_nt_error_from_unix -- don't want to link in
314 * errormap.o into lots of utils.
315 */
316
317 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
318 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
319 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
320 return NT_STATUS_UNSUCCESSFUL;
321}
322
323/****************************************************************************
324 Send a message to a particular pid.
325****************************************************************************/
326
327static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
328 struct server_id pid, int msg_type,
329 const DATA_BLOB *data,
330 struct messaging_backend *backend)
331{
332 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
333 struct messaging_tdb_context);
334 struct messaging_array *msg_array;
335 struct messaging_rec *rec;
336 NTSTATUS status;
337 TDB_DATA key;
338 struct tdb_wrap *tdb = ctx->tdb;
339 TALLOC_CTX *frame = talloc_stackframe();
340
341 /* NULL pointer means implicit length zero. */
342 if (!data->data) {
343 SMB_ASSERT(data->length == 0);
344 }
345
346 /*
347 * Doing kill with a non-positive pid causes messages to be
348 * sent to places we don't want.
349 */
350
351 SMB_ASSERT(procid_to_pid(&pid) > 0);
352
353 key = message_key_pid(frame, pid);
354
355 if (tdb_chainlock(tdb->tdb, key) == -1) {
356 TALLOC_FREE(frame);
357 return NT_STATUS_LOCK_NOT_GRANTED;
358 }
359
360 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
361
362 if (!NT_STATUS_IS_OK(status)) {
363 goto done;
364 }
365
366 if ((msg_type & MSG_FLAG_LOWPRIORITY)
367 && (msg_array->num_messages > 1000)) {
368 DEBUG(5, ("Dropping message for PID %s\n",
369 procid_str_static(&pid)));
370 status = NT_STATUS_INSUFFICIENT_RESOURCES;
371 goto done;
372 }
373
374 if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages,
375 struct messaging_rec,
376 msg_array->num_messages+1))) {
377 status = NT_STATUS_NO_MEMORY;
378 goto done;
379 }
380
381 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
382 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
383 rec[msg_array->num_messages].dest = pid;
384 rec[msg_array->num_messages].src = msg_ctx->id;
385 rec[msg_array->num_messages].buf = *data;
386
387 msg_array->messages = rec;
388 msg_array->num_messages += 1;
389
390 status = messaging_tdb_store(tdb->tdb, key, msg_array);
391
392 if (!NT_STATUS_IS_OK(status)) {
393 goto done;
394 }
395
396 status = message_notify(pid);
397
398 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
399 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
400 procid_str_static(&pid)));
401 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
402 }
403
404 done:
405 tdb_chainunlock(tdb->tdb, key);
406 TALLOC_FREE(frame);
407 return status;
408}
409
410/****************************************************************************
411 Retrieve all messages for a process.
412****************************************************************************/
413
414static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
415 struct server_id id,
416 TALLOC_CTX *mem_ctx,
417 struct messaging_array **presult)
418{
419 struct messaging_array *result;
420 TDB_DATA key = message_key_pid(mem_ctx, id);
421 NTSTATUS status;
422
423 if (tdb_chainlock(msg_tdb, key) == -1) {
424 TALLOC_FREE(key.dptr);
425 return NT_STATUS_LOCK_NOT_GRANTED;
426 }
427
428 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
429
430 /*
431 * We delete the record here, tdb_set_max_dead keeps it around
432 */
433 tdb_delete(msg_tdb, key);
434 tdb_chainunlock(msg_tdb, key);
435
436 if (NT_STATUS_IS_OK(status)) {
437 *presult = result;
438 }
439
440 TALLOC_FREE(key.dptr);
441
442 return status;
443}
444
445/****************************************************************************
446 Receive and dispatch any messages pending for this process.
447 JRA changed Dec 13 2006. Only one message handler now permitted per type.
448 *NOTE*: Dispatch functions must be able to cope with incoming
449 messages on an *odd* byte boundary.
450****************************************************************************/
451
452static void message_dispatch(struct messaging_context *msg_ctx)
453{
454 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
455 struct messaging_tdb_context);
456 struct messaging_array *msg_array = NULL;
457 struct tdb_wrap *tdb = ctx->tdb;
458 NTSTATUS status;
459 uint32 i;
460
461 if (ctx->received_messages == 0) {
462 return;
463 }
464
465 DEBUG(10, ("message_dispatch: received_messages = %d\n",
466 ctx->received_messages));
467
468 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
469 if (!NT_STATUS_IS_OK(status)) {
470 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
471 nt_errstr(status)));
472 return;
473 }
474
475 ctx->received_messages = 0;
476
477 for (i=0; i<msg_array->num_messages; i++) {
478 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
479 }
480
481 TALLOC_FREE(msg_array);
482}
483
484/** @} **/
Note: See TracBrowser for help on using the repository browser.