2 * Unix SMB/CIFS implementation.
3 * Samba internal messaging functions
4 * Copyright (C) 2013 by Volker Lendecke
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.
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.
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/>.
21 #include "lib/util/data_blob.h"
22 #include "lib/util/debug.h"
23 #include "lib/unix_msg/unix_msg.h"
24 #include "system/filesys.h"
26 #include "lib/param/param.h"
27 #include "poll_funcs/poll_funcs_tevent.h"
28 #include "unix_msg/unix_msg.h"
29 #include "librpc/gen_ndr/messaging.h"
31 struct messaging_dgm_context
{
32 struct messaging_context
*msg_ctx
;
33 struct poll_funcs
*msg_callbacks
;
35 struct unix_msg_ctx
*dgm_ctx
;
40 struct messaging_dgm_hdr
{
42 enum messaging_type msg_type
;
47 static NTSTATUS
messaging_dgm_send(struct messaging_context
*msg_ctx
,
48 struct server_id pid
, int msg_type
,
49 const struct iovec
*iov
, int iovlen
,
50 struct messaging_backend
*backend
);
51 static void messaging_dgm_recv(struct unix_msg_ctx
*ctx
,
52 uint8_t *msg
, size_t msg_len
,
55 static int messaging_dgm_context_destructor(struct messaging_dgm_context
*c
);
57 static int messaging_dgm_lockfile_create(const char *cache_dir
, pid_t pid
,
58 int *plockfile_fd
, uint64_t unique
)
65 struct flock lck
= {};
70 dirlen
= full_path_tos(cache_dir
, "lck", buf
, sizeof(buf
),
76 ok
= directory_create_or_exist_strict(dir
, sec_initial_uid(), 0755);
79 DEBUG(1, ("%s: Could not create lock directory: %s\n",
80 __func__
, strerror(ret
)));
85 lockfile_name
= talloc_asprintf(talloc_tos(), "%s/%u", dir
,
88 if (lockfile_name
== NULL
) {
89 DEBUG(1, ("%s: talloc_asprintf failed\n", __func__
));
93 /* no O_EXCL, existence check is via the fcntl lock */
95 lockfile_fd
= open(lockfile_name
, O_NONBLOCK
|O_CREAT
|O_WRONLY
, 0644);
96 if (lockfile_fd
== -1) {
98 DEBUG(1, ("%s: open failed: %s\n", __func__
, strerror(errno
)));
102 lck
.l_type
= F_WRLCK
;
103 lck
.l_whence
= SEEK_SET
;
107 ret
= fcntl(lockfile_fd
, F_SETLK
, &lck
);
110 DEBUG(1, ("%s: fcntl failed: %s\n", __func__
, strerror(ret
)));
114 unique_len
= snprintf(buf
, sizeof(buf
), "%"PRIu64
, unique
);
116 /* shorten a potentially preexisting file */
118 ret
= ftruncate(lockfile_fd
, unique_len
);
121 DEBUG(1, ("%s: ftruncate failed: %s\n", __func__
,
126 written
= write(lockfile_fd
, buf
, unique_len
);
127 if (written
!= unique_len
) {
129 DEBUG(1, ("%s: write failed: %s\n", __func__
, strerror(ret
)));
133 *plockfile_fd
= lockfile_fd
;
137 unlink(lockfile_name
);
141 TALLOC_FREE(lockfile_name
);
145 static int messaging_dgm_lockfile_remove(const char *cache_dir
, pid_t pid
)
149 char *lockfile_name
, *to_free
;
153 fstr_sprintf(fname
, "lck/%u", (unsigned)pid
);
155 len
= full_path_tos(cache_dir
, fname
, buf
, sizeof(buf
),
156 &lockfile_name
, &to_free
);
161 ret
= unlink(lockfile_name
);
164 DEBUG(10, ("%s: unlink failed: %s\n", __func__
,
167 TALLOC_FREE(to_free
);
171 NTSTATUS
messaging_dgm_init(struct messaging_context
*msg_ctx
,
173 struct messaging_backend
**presult
)
175 struct messaging_backend
*result
;
176 struct messaging_dgm_context
*ctx
;
177 struct server_id pid
= messaging_server_id(msg_ctx
);
180 const char *cache_dir
;
181 char *socket_dir
, *socket_name
;
184 cache_dir
= lp_cache_directory();
185 if (cache_dir
== NULL
) {
186 NTSTATUS status
= map_nt_error_from_unix(errno
);
190 result
= talloc(mem_ctx
, struct messaging_backend
);
191 if (result
== NULL
) {
194 ctx
= talloc_zero(result
, struct messaging_dgm_context
);
199 result
->private_data
= ctx
;
200 result
->send_fn
= messaging_dgm_send
;
201 ctx
->msg_ctx
= msg_ctx
;
203 ctx
->cache_dir
= talloc_strdup(ctx
, cache_dir
);
204 if (ctx
->cache_dir
== NULL
) {
207 socket_dir
= talloc_asprintf(ctx
, "%s/msg", cache_dir
);
208 if (socket_dir
== NULL
) {
211 socket_name
= talloc_asprintf(ctx
, "%s/%u", socket_dir
,
213 if (socket_name
== NULL
) {
219 ret
= messaging_dgm_lockfile_create(cache_dir
, pid
.pid
,
220 &ctx
->lockfile_fd
, pid
.unique_id
);
222 DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
223 __func__
, strerror(ret
)));
225 return map_nt_error_from_unix(ret
);
228 ctx
->msg_callbacks
= poll_funcs_init_tevent(ctx
);
229 if (ctx
->msg_callbacks
== NULL
) {
231 return NT_STATUS_NO_MEMORY
;
234 ctx
->tevent_handle
= poll_funcs_tevent_register(
235 ctx
, ctx
->msg_callbacks
, msg_ctx
->event_ctx
);
236 if (ctx
->tevent_handle
== NULL
) {
238 return NT_STATUS_NO_MEMORY
;
241 ok
= directory_create_or_exist_strict(socket_dir
, sec_initial_uid(),
244 DEBUG(1, ("Could not create socket directory\n"));
246 return NT_STATUS_ACCESS_DENIED
;
248 TALLOC_FREE(socket_dir
);
252 generate_random_buffer((uint8_t *)&cookie
, sizeof(cookie
));
254 ret
= unix_msg_init(socket_name
, ctx
->msg_callbacks
, 1024, cookie
,
255 messaging_dgm_recv
, ctx
, &ctx
->dgm_ctx
);
256 TALLOC_FREE(socket_name
);
258 DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret
)));
260 return map_nt_error_from_unix(ret
);
262 talloc_set_destructor(ctx
, messaging_dgm_context_destructor
);
269 return NT_STATUS_NO_MEMORY
;
272 static int messaging_dgm_context_destructor(struct messaging_dgm_context
*c
)
274 struct server_id pid
= messaging_server_id(c
->msg_ctx
);
277 * First delete the socket to avoid races. The lockfile is the
278 * indicator that we're still around.
280 unix_msg_free(c
->dgm_ctx
);
282 if (getpid() == pid
.pid
) {
283 (void)messaging_dgm_lockfile_remove(c
->cache_dir
, pid
.pid
);
285 close(c
->lockfile_fd
);
289 static NTSTATUS
messaging_dgm_send(struct messaging_context
*msg_ctx
,
290 struct server_id pid
, int msg_type
,
291 const struct iovec
*iov
, int iovlen
,
292 struct messaging_backend
*backend
)
294 struct messaging_dgm_context
*ctx
= talloc_get_type_abort(
295 backend
->private_data
, struct messaging_dgm_context
);
298 char *dst_sock
, *to_free
;
299 struct messaging_dgm_hdr hdr
;
300 struct iovec iov2
[iovlen
+ 1];
304 fstr_sprintf(pid_str
, "msg/%u", (unsigned)pid
.pid
);
306 pathlen
= full_path_tos(ctx
->cache_dir
, pid_str
, buf
, sizeof(buf
),
307 &dst_sock
, &to_free
);
309 return NT_STATUS_NO_MEMORY
;
312 hdr
.msg_version
= MESSAGE_VERSION
;
313 hdr
.msg_type
= msg_type
& MSG_TYPE_MASK
;
315 hdr
.src
= msg_ctx
->id
;
317 DEBUG(10, ("%s: Sending message 0x%x to %s\n", __func__
,
318 (unsigned)hdr
.msg_type
,
319 server_id_str(talloc_tos(), &pid
)));
321 iov2
[0].iov_base
= &hdr
;
322 iov2
[0].iov_len
= sizeof(hdr
);
323 memcpy(iov2
+1, iov
, iovlen
*sizeof(struct iovec
));
326 ret
= unix_msg_send(ctx
->dgm_ctx
, dst_sock
, iov2
, iovlen
+ 1);
329 TALLOC_FREE(to_free
);
332 return map_nt_error_from_unix(ret
);
337 static void messaging_dgm_recv(struct unix_msg_ctx
*ctx
,
338 uint8_t *msg
, size_t msg_len
,
341 struct messaging_dgm_context
*dgm_ctx
= talloc_get_type_abort(
342 private_data
, struct messaging_dgm_context
);
343 struct messaging_dgm_hdr
*hdr
;
344 struct messaging_rec rec
;
346 if (msg_len
< sizeof(*hdr
)) {
347 DEBUG(1, ("message too short: %u\n", (unsigned)msg_len
));
352 * unix_msg guarantees alignment, so we can cast here
354 hdr
= (struct messaging_dgm_hdr
*)msg
;
356 rec
.msg_version
= hdr
->msg_version
;
357 rec
.msg_type
= hdr
->msg_type
;
360 rec
.buf
.data
= msg
+ sizeof(*hdr
);
361 rec
.buf
.length
= msg_len
- sizeof(*hdr
);
363 DEBUG(10, ("%s: Received message 0x%x len %u from %s\n", __func__
,
364 (unsigned)hdr
->msg_type
, (unsigned)rec
.buf
.length
,
365 server_id_str(talloc_tos(), &rec
.src
)));
367 messaging_dispatch_rec(dgm_ctx
->msg_ctx
, &rec
);
370 NTSTATUS
messaging_dgm_cleanup(struct messaging_context
*msg_ctx
, pid_t pid
)
372 struct messaging_dgm_context
*ctx
= talloc_get_type_abort(
373 msg_ctx
->local
->private_data
, struct messaging_dgm_context
);
374 char *lockfile_name
, *socket_name
;
376 struct flock lck
= {};
377 NTSTATUS status
= NT_STATUS_OK
;
379 lockfile_name
= talloc_asprintf(talloc_tos(), "%s/lck/%u",
380 ctx
->cache_dir
, (unsigned)pid
);
381 if (lockfile_name
== NULL
) {
382 return NT_STATUS_NO_MEMORY
;
384 socket_name
= talloc_asprintf(lockfile_name
, "%s/msg/%u",
385 ctx
->cache_dir
, (unsigned)pid
);
386 if (socket_name
== NULL
) {
387 TALLOC_FREE(lockfile_name
);
388 return NT_STATUS_NO_MEMORY
;
391 fd
= open(lockfile_name
, O_NONBLOCK
|O_WRONLY
, 0);
393 status
= map_nt_error_from_unix(errno
);
394 DEBUG(10, ("%s: open(%s) failed: %s\n", __func__
,
395 lockfile_name
, strerror(errno
)));
399 lck
.l_type
= F_WRLCK
;
400 lck
.l_whence
= SEEK_SET
;
404 ret
= fcntl(fd
, F_SETLK
, &lck
);
406 status
= map_nt_error_from_unix(errno
);
407 DEBUG(10, ("%s: Could not get lock: %s\n", __func__
,
409 TALLOC_FREE(lockfile_name
);
414 (void)unlink(socket_name
);
415 (void)unlink(lockfile_name
);
418 TALLOC_FREE(lockfile_name
);
422 NTSTATUS
messaging_dgm_wipe(struct messaging_context
*msg_ctx
)
424 struct messaging_dgm_context
*ctx
= talloc_get_type_abort(
425 msg_ctx
->local
->private_data
, struct messaging_dgm_context
);
429 pid_t our_pid
= getpid();
432 * We scan the socket directory and not the lock directory. Otherwise
433 * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
437 msgdir_name
= talloc_asprintf(talloc_tos(), "%s/msg", ctx
->cache_dir
);
438 if (msgdir_name
== NULL
) {
439 return NT_STATUS_NO_MEMORY
;
442 msgdir
= opendir(msgdir_name
);
443 TALLOC_FREE(msgdir_name
);
444 if (msgdir
== NULL
) {
445 return map_nt_error_from_unix(errno
);
448 while ((dp
= readdir(msgdir
)) != NULL
) {
452 pid
= strtoul(dp
->d_name
, NULL
, 10);
455 * . and .. and other malformed entries
459 if (pid
== our_pid
) {
461 * fcntl(F_GETLK) will succeed for ourselves, we hold
462 * that lock ourselves.
467 status
= messaging_dgm_cleanup(msg_ctx
, pid
);
468 DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
469 pid
, nt_errstr(status
)));
476 void *messaging_dgm_register_tevent_context(TALLOC_CTX
*mem_ctx
,
477 struct messaging_context
*msg_ctx
,
478 struct tevent_context
*ev
)
480 struct messaging_dgm_context
*ctx
= talloc_get_type_abort(
481 msg_ctx
->local
->private_data
, struct messaging_dgm_context
);
482 return poll_funcs_tevent_register(mem_ctx
, ctx
->msg_callbacks
, ev
);