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