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 49struct 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 56static 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); 60static void message_dispatch(struct messaging_context *msg_ctx); 61 62static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx, 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 82NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx, 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"), 0, 106 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE, 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 *presult = result; 133 return NT_STATUS_OK; 134} 135 136/******************************************************************* 137 Form a static tdb key from a pid. 138******************************************************************/ 139 140static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid) 141{ 142 char *key; 143 TDB_DATA kbuf; 144 145 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid)); 146 147 SMB_ASSERT(key != NULL); 148 149 kbuf.dptr = (uint8 *)key; 150 kbuf.dsize = strlen(key)+1; 151 return kbuf; 152} 153 154/* 155 Fetch the messaging array for a process 156 */ 157 158static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb, 159 TDB_DATA key, 160 TALLOC_CTX *mem_ctx, 161 struct messaging_array **presult) 162{ 163 struct messaging_array *result; 164 TDB_DATA data; 165 DATA_BLOB blob; 166 enum ndr_err_code ndr_err; 167 168 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) { 169 return NT_STATUS_NO_MEMORY; 170 } 171 172 data = tdb_fetch(msg_tdb, key); 173 174 if (data.dptr == NULL) { 175 *presult = result; 176 return NT_STATUS_OK; 177 } 178 179 blob = data_blob_const(data.dptr, data.dsize); 180 181 ndr_err = ndr_pull_struct_blob( 182 &blob, result, NULL, result, 183 (ndr_pull_flags_fn_t)ndr_pull_messaging_array); 184 185 SAFE_FREE(data.dptr); 186 187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 188 TALLOC_FREE(result); 189 return ndr_map_error2ntstatus(ndr_err); 190 } 191 192 if (DEBUGLEVEL >= 10) { 193 DEBUG(10, ("messaging_tdb_fetch:\n")); 194 NDR_PRINT_DEBUG(messaging_array, result); 195 } 196 197 *presult = result; 198 return NT_STATUS_OK; 199} 200 201/* 202 Store a messaging array for a pid 203*/ 204 205static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb, 206 TDB_DATA key, 207 struct messaging_array *array) 208{ 209 TDB_DATA data; 210 DATA_BLOB blob; 211 enum ndr_err_code ndr_err; 212 TALLOC_CTX *mem_ctx; 213 int ret; 214 215 if (array->num_messages == 0) { 216 tdb_delete(msg_tdb, key); 217 return NT_STATUS_OK; 218 } 219 220 if (!(mem_ctx = talloc_new(array))) { 221 return NT_STATUS_NO_MEMORY; 222 } 223 224 ndr_err = ndr_push_struct_blob( 225 &blob, mem_ctx, NULL, array, 226 (ndr_push_flags_fn_t)ndr_push_messaging_array); 227 228 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 229 talloc_free(mem_ctx); 230 return ndr_map_error2ntstatus(ndr_err); 231 } 232 233 if (DEBUGLEVEL >= 10) { 234 DEBUG(10, ("messaging_tdb_store:\n")); 235 NDR_PRINT_DEBUG(messaging_array, array); 236 } 237 238 data.dptr = blob.data; 239 data.dsize = blob.length; 240 241 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE); 242 TALLOC_FREE(mem_ctx); 243 244 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION; 245} 246 247/**************************************************************************** 248 Notify a process that it has a message. If the process doesn't exist 249 then delete its record in the database. 250****************************************************************************/ 251 252static NTSTATUS message_notify(struct server_id procid) 253{ 254 pid_t pid = procid.pid; 255 int ret; 256 uid_t euid = geteuid(); 257 258 /* 259 * Doing kill with a non-positive pid causes messages to be 260 * sent to places we don't want. 261 */ 262 263 SMB_ASSERT(pid > 0); 264 265 if (euid != 0) { 266 /* If we're not root become so to send the message. */ 267 save_re_uid(); 268 set_effective_uid(0); 269 } 270 271 ret = kill(pid, SIGUSR1); 272 273 if (euid != 0) { 274 /* Go back to who we were. */ 275 int saved_errno = errno; 276 restore_re_uid_fromroot(); 277 errno = saved_errno; 278 } 279 280 if (ret == 0) { 281 return NT_STATUS_OK; 282 } 283 284 /* 285 * Something has gone wrong 286 */ 287 288 DEBUG(2,("message to process %d failed - %s\n", (int)pid, 289 strerror(errno))); 290 291 /* 292 * No call to map_nt_error_from_unix -- don't want to link in 293 * errormap.o into lots of utils. 294 */ 295 296 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE; 297 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER; 298 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED; 299 return NT_STATUS_UNSUCCESSFUL; 300} 301 302/**************************************************************************** 303 Send a message to a particular pid. 304****************************************************************************/ 305 306static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx, 307 struct server_id pid, int msg_type, 308 const DATA_BLOB *data, 309 struct messaging_backend *backend) 310{ 311 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data, 312 struct messaging_tdb_context); 313 struct messaging_array *msg_array; 314 struct messaging_rec *rec; 315 NTSTATUS status; 316 TDB_DATA key; 317 struct tdb_wrap *tdb = ctx->tdb; 318 TALLOC_CTX *frame = talloc_stackframe(); 319 320 /* NULL pointer means implicit length zero. */ 321 if (!data->data) { 322 SMB_ASSERT(data->length == 0); 323 } 324 325 /* 326 * Doing kill with a non-positive pid causes messages to be 327 * sent to places we don't want. 328 */ 329 330 SMB_ASSERT(procid_to_pid(&pid) > 0); 331 332 key = message_key_pid(frame, pid); 333 334 if (tdb_chainlock(tdb->tdb, key) == -1) { 335 TALLOC_FREE(frame); 336 return NT_STATUS_LOCK_NOT_GRANTED; 337 } 338 339 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array); 340 341 if (!NT_STATUS_IS_OK(status)) { 342 goto done; 343 } 344 345 if ((msg_type & MSG_FLAG_LOWPRIORITY) 346 && (msg_array->num_messages > 1000)) { 347 DEBUG(5, ("Dropping message for PID %s\n", 348 procid_str_static(&pid))); 349 status = NT_STATUS_INSUFFICIENT_RESOURCES; 350 goto done; 351 } 352 353 if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages, 354 struct messaging_rec, 355 msg_array->num_messages+1))) { 356 status = NT_STATUS_NO_MEMORY; 357 goto done; 358 } 359 360 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION; 361 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK; 362 rec[msg_array->num_messages].dest = pid; 363 rec[msg_array->num_messages].src = procid_self(); 364 rec[msg_array->num_messages].buf = *data; 365 366 msg_array->messages = rec; 367 msg_array->num_messages += 1; 368 369 status = messaging_tdb_store(tdb->tdb, key, msg_array); 370 371 if (!NT_STATUS_IS_OK(status)) { 372 goto done; 373 } 374 375 status = message_notify(pid); 376 377 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { 378 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n", 379 procid_str_static(&pid))); 380 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid)); 381 } 382 383 done: 384 tdb_chainunlock(tdb->tdb, key); 385 TALLOC_FREE(frame); 386 return status; 387} 388 389/**************************************************************************** 390 Retrieve all messages for the current process. 391****************************************************************************/ 392 393static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb, 394 TALLOC_CTX *mem_ctx, 395 struct messaging_array **presult) 396{ 397 struct messaging_array *result; 398 TDB_DATA key = message_key_pid(mem_ctx, procid_self()); 399 NTSTATUS status; 400 401 if (tdb_chainlock(msg_tdb, key) == -1) { 402 TALLOC_FREE(key.dptr); 403 return NT_STATUS_LOCK_NOT_GRANTED; 404 } 405 406 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result); 407 408 /* 409 * We delete the record here, tdb_set_max_dead keeps it around 410 */ 411 tdb_delete(msg_tdb, key); 412 tdb_chainunlock(msg_tdb, key); 413 414 if (NT_STATUS_IS_OK(status)) { 415 *presult = result; 416 } 417 418 TALLOC_FREE(key.dptr); 419 420 return status; 421} 422 423/**************************************************************************** 424 Receive and dispatch any messages pending for this process. 425 JRA changed Dec 13 2006. Only one message handler now permitted per type. 426 *NOTE*: Dispatch functions must be able to cope with incoming 427 messages on an *odd* byte boundary. 428****************************************************************************/ 429 430static void message_dispatch(struct messaging_context *msg_ctx) 431{ 432 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data, 433 struct messaging_tdb_context); 434 struct messaging_array *msg_array = NULL; 435 struct tdb_wrap *tdb = ctx->tdb; 436 NTSTATUS status; 437 uint32 i; 438 439 if (ctx->received_messages == 0) { 440 return; 441 } 442 443 DEBUG(10, ("message_dispatch: received_messages = %d\n", 444 ctx->received_messages)); 445 446 status = retrieve_all_messages(tdb->tdb, NULL, &msg_array); 447 if (!NT_STATUS_IS_OK(status)) { 448 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n", 449 nt_errstr(status))); 450 return; 451 } 452 453 ctx->received_messages = 0; 454 455 for (i=0; i<msg_array->num_messages; i++) { 456 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]); 457 } 458 459 TALLOC_FREE(msg_array); 460} 461 462/** @} **/ 463