r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[ira/wip.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 int 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         TDB_CONTEXT *tdb = (TDB_CONTEXT *)tdb_ctx->private_data;
69         tdb_close(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         TDB_CONTEXT *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_open_log(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, 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(struct server_id pid)
122 {
123         static char key[20];
124         TDB_DATA kbuf;
125
126         slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
127         
128         kbuf.dptr = (uint8 *)key;
129         kbuf.dsize = strlen(key)+1;
130         return kbuf;
131 }
132
133 /*
134   Fetch the messaging array for a process
135  */
136
137 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
138                                     TDB_DATA key,
139                                     TALLOC_CTX *mem_ctx,
140                                     struct messaging_array **presult)
141 {
142         struct messaging_array *result;
143         TDB_DATA data;
144         DATA_BLOB blob;
145         NTSTATUS status;
146
147         if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
148                 return NT_STATUS_NO_MEMORY;
149         }
150
151         data = tdb_fetch(msg_tdb, key);
152
153         if (data.dptr == NULL) {
154                 *presult = result;
155                 return NT_STATUS_OK;
156         }
157
158         blob = data_blob_const(data.dptr, data.dsize);
159
160         status = ndr_pull_struct_blob(
161                 &blob, result, result,
162                 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
163
164         SAFE_FREE(data.dptr);
165
166         if (!NT_STATUS_IS_OK(status)) {
167                 TALLOC_FREE(result);
168                 return status;
169         }
170
171         if (DEBUGLEVEL >= 10) {
172                 DEBUG(10, ("messaging_tdb_fetch:\n"));
173                 NDR_PRINT_DEBUG(messaging_array, result);
174         }
175
176         *presult = result;
177         return NT_STATUS_OK;
178 }
179
180 /*
181   Store a messaging array for a pid
182 */
183
184 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
185                                     TDB_DATA key,
186                                     struct messaging_array *array)
187 {
188         TDB_DATA data;
189         DATA_BLOB blob;
190         NTSTATUS status;
191         TALLOC_CTX *mem_ctx;
192         int ret;
193
194         if (array->num_messages == 0) {
195                 tdb_delete(msg_tdb, key);
196                 return NT_STATUS_OK;
197         }
198
199         if (!(mem_ctx = talloc_new(array))) {
200                 return NT_STATUS_NO_MEMORY;
201         }
202
203         status = ndr_push_struct_blob(
204                 &blob, mem_ctx, array,
205                 (ndr_push_flags_fn_t)ndr_push_messaging_array);
206
207         if (!NT_STATUS_IS_OK(status)) {
208                 talloc_free(mem_ctx);
209                 return status;
210         }
211
212         if (DEBUGLEVEL >= 10) {
213                 DEBUG(10, ("messaging_tdb_store:\n"));
214                 NDR_PRINT_DEBUG(messaging_array, array);
215         }
216
217         data.dptr = blob.data;
218         data.dsize = blob.length;
219
220         ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
221         TALLOC_FREE(mem_ctx);
222
223         return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
224 }
225
226 /****************************************************************************
227  Notify a process that it has a message. If the process doesn't exist 
228  then delete its record in the database.
229 ****************************************************************************/
230
231 static NTSTATUS message_notify(struct server_id procid)
232 {
233         pid_t pid = procid.pid;
234         int ret;
235         uid_t euid = geteuid();
236
237         /*
238          * Doing kill with a non-positive pid causes messages to be
239          * sent to places we don't want.
240          */
241
242         SMB_ASSERT(pid > 0);
243
244         if (euid != 0) {
245                 /* If we're not root become so to send the message. */
246                 save_re_uid();
247                 set_effective_uid(0);
248         }
249
250         ret = kill(pid, SIGUSR1);
251
252         if (euid != 0) {
253                 /* Go back to who we were. */
254                 int saved_errno = errno;
255                 restore_re_uid_fromroot();
256                 errno = saved_errno;
257         }
258
259         if (ret == 0) {
260                 return NT_STATUS_OK;
261         }
262
263         /*
264          * Something has gone wrong
265          */
266
267         DEBUG(2,("message to process %d failed - %s\n", (int)pid,
268                  strerror(errno)));
269
270         /*
271          * No call to map_nt_error_from_unix -- don't want to link in
272          * errormap.o into lots of utils.
273          */
274
275         if (errno == ESRCH)  return NT_STATUS_INVALID_HANDLE;
276         if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
277         if (errno == EPERM)  return NT_STATUS_ACCESS_DENIED;
278         return NT_STATUS_UNSUCCESSFUL;
279 }
280
281 /****************************************************************************
282  Send a message to a particular pid.
283 ****************************************************************************/
284
285 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
286                                    struct server_id pid, int msg_type,
287                                    const DATA_BLOB *data,
288                                    struct messaging_backend *backend)
289 {
290         struct messaging_array *msg_array;
291         struct messaging_rec *rec;
292         TALLOC_CTX *mem_ctx;
293         NTSTATUS status;
294         TDB_DATA key = message_key_pid(pid);
295         TDB_CONTEXT *tdb = (TDB_CONTEXT *)backend->private_data;
296
297         /* NULL pointer means implicit length zero. */
298         if (!data->data) {
299                 SMB_ASSERT(data->length == 0);
300         }
301
302         /*
303          * Doing kill with a non-positive pid causes messages to be
304          * sent to places we don't want.
305          */
306
307         SMB_ASSERT(procid_to_pid(&pid) > 0);
308
309         if (!(mem_ctx = talloc_init("message_send_pid"))) {
310                 return NT_STATUS_NO_MEMORY;
311         }
312
313         if (tdb_chainlock(tdb, key) == -1) {
314                 TALLOC_FREE(mem_ctx);
315                 return NT_STATUS_LOCK_NOT_GRANTED;
316         }
317
318         status = messaging_tdb_fetch(tdb, key, mem_ctx, &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(mem_ctx, 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, 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, message_key_pid(pid));
360         }
361
362  done:
363         tdb_chainunlock(tdb, key);
364         TALLOC_FREE(mem_ctx);
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(procid_self());
378         NTSTATUS status;
379
380         if (tdb_chainlock(msg_tdb, key) == -1) {
381                 return NT_STATUS_LOCK_NOT_GRANTED;
382         }
383
384         status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
385
386         /*
387          * We delete the record here, tdb_set_max_dead keeps it around
388          */
389         tdb_delete(msg_tdb, key);
390         tdb_chainunlock(msg_tdb, key);
391
392         if (NT_STATUS_IS_OK(status)) {
393                 *presult = result;
394         }
395
396         return status;
397 }
398
399 /****************************************************************************
400  Receive and dispatch any messages pending for this process.
401  JRA changed Dec 13 2006. Only one message handler now permitted per type.
402  *NOTE*: Dispatch functions must be able to cope with incoming
403  messages on an *odd* byte boundary.
404 ****************************************************************************/
405
406 void message_dispatch(struct messaging_context *msg_ctx)
407 {
408         struct messaging_array *msg_array = NULL;
409         TDB_CONTEXT *tdb = (TDB_CONTEXT *)(msg_ctx->local->private_data);
410         uint32 i;
411
412         if (!received_signal)
413                 return;
414
415         DEBUG(10, ("message_dispatch: received_signal = %d\n",
416                    received_signal));
417
418         received_signal = 0;
419
420         if (!NT_STATUS_IS_OK(retrieve_all_messages(tdb, NULL, &msg_array))) {
421                 return;
422         }
423
424         for (i=0; i<msg_array->num_messages; i++) {
425                 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
426         }
427
428         TALLOC_FREE(msg_array);
429 }
430
431 /** @} **/