1*e89934bbSchristos /* $NetBSD: pass_trigger.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */
2e6ca80d4Stron
3e6ca80d4Stron /*++
4e6ca80d4Stron /* NAME
5e6ca80d4Stron /* pass_trigger 3
6e6ca80d4Stron /* SUMMARY
7e6ca80d4Stron /* trigger file descriptor listener
8e6ca80d4Stron /* SYNOPSIS
9e6ca80d4Stron /* #include <trigger.h>
10e6ca80d4Stron /*
11e6ca80d4Stron /* int pass_trigger(service, buf, len, timeout)
12e6ca80d4Stron /* const char *service;
13e6ca80d4Stron /* const char *buf;
14e6ca80d4Stron /* ssize_t len;
15e6ca80d4Stron /* int timeout;
16e6ca80d4Stron /* DESCRIPTION
17e6ca80d4Stron /* pass_trigger() connects to the named local server by sending
18e6ca80d4Stron /* a file descriptor to it and writing the named buffer.
19e6ca80d4Stron /*
20e6ca80d4Stron /* The connection is closed by a background thread. Some kernels
21e6ca80d4Stron /* cannot handle client-side disconnect before the server has
22e6ca80d4Stron /* received the message.
23e6ca80d4Stron /*
24e6ca80d4Stron /* Arguments:
25e6ca80d4Stron /* .IP service
26e6ca80d4Stron /* Name of the communication endpoint.
27e6ca80d4Stron /* .IP buf
28e6ca80d4Stron /* Address of data to be written.
29e6ca80d4Stron /* .IP len
30e6ca80d4Stron /* Amount of data to be written.
31e6ca80d4Stron /* .IP timeout
32e6ca80d4Stron /* Deadline in seconds. Specify a value <= 0 to disable
33e6ca80d4Stron /* the time limit.
34e6ca80d4Stron /* DIAGNOSTICS
35e6ca80d4Stron /* The result is zero in case of success, -1 in case of problems.
36e6ca80d4Stron /* SEE ALSO
37e6ca80d4Stron /* unix_connect(3), local client
38e6ca80d4Stron /* stream_connect(3), streams-based client
39e6ca80d4Stron /* LICENSE
40e6ca80d4Stron /* .ad
41e6ca80d4Stron /* .fi
42e6ca80d4Stron /* The Secure Mailer license must be distributed with this software.
43e6ca80d4Stron /* AUTHOR(S)
44e6ca80d4Stron /* Wietse Venema
45e6ca80d4Stron /* IBM T.J. Watson Research
46e6ca80d4Stron /* P.O. Box 704
47e6ca80d4Stron /* Yorktown Heights, NY 10598, USA
48e6ca80d4Stron /*--*/
49e6ca80d4Stron
50e6ca80d4Stron /* System library. */
51e6ca80d4Stron
52e6ca80d4Stron #include <sys_defs.h>
53e6ca80d4Stron #include <sys/socket.h>
54e6ca80d4Stron #include <unistd.h>
55e6ca80d4Stron #include <string.h>
56e6ca80d4Stron
57e6ca80d4Stron /* Utility library. */
58e6ca80d4Stron
59e6ca80d4Stron #include <msg.h>
60e6ca80d4Stron #include <connect.h>
61e6ca80d4Stron #include <iostuff.h>
62e6ca80d4Stron #include <mymalloc.h>
63e6ca80d4Stron #include <events.h>
64e6ca80d4Stron #include <trigger.h>
65e6ca80d4Stron
66e6ca80d4Stron struct pass_trigger {
67e6ca80d4Stron int connect_fd;
68e6ca80d4Stron char *service;
69e6ca80d4Stron int pass_fd[2];
70e6ca80d4Stron };
71e6ca80d4Stron
72e6ca80d4Stron /* pass_trigger_event - disconnect from peer */
73e6ca80d4Stron
pass_trigger_event(int event,void * context)74e262b48eSchristos static void pass_trigger_event(int event, void *context)
75e6ca80d4Stron {
76e6ca80d4Stron struct pass_trigger *pp = (struct pass_trigger *) context;
77e6ca80d4Stron static const char *myname = "pass_trigger_event";
78e6ca80d4Stron
79e6ca80d4Stron /*
80e6ca80d4Stron * Disconnect.
81e6ca80d4Stron */
82e6ca80d4Stron if (event == EVENT_TIME)
83e6ca80d4Stron msg_warn("%s: read timeout for service %s", myname, pp->service);
84e6ca80d4Stron event_disable_readwrite(pp->connect_fd);
85e6ca80d4Stron event_cancel_timer(pass_trigger_event, context);
86e6ca80d4Stron /* Don't combine multiple close() calls into one boolean expression. */
87e6ca80d4Stron if (close(pp->connect_fd) < 0)
88e6ca80d4Stron msg_warn("%s: close %s: %m", myname, pp->service);
89e6ca80d4Stron if (close(pp->pass_fd[0]) < 0)
90e6ca80d4Stron msg_warn("%s: close pipe: %m", myname);
91e6ca80d4Stron if (close(pp->pass_fd[1]) < 0)
92e6ca80d4Stron msg_warn("%s: close pipe: %m", myname);
93e6ca80d4Stron myfree(pp->service);
94e262b48eSchristos myfree((void *) pp);
95e6ca80d4Stron }
96e6ca80d4Stron
97e6ca80d4Stron /* pass_trigger - wakeup local server */
98e6ca80d4Stron
pass_trigger(const char * service,const char * buf,ssize_t len,int timeout)99e6ca80d4Stron int pass_trigger(const char *service, const char *buf, ssize_t len, int timeout)
100e6ca80d4Stron {
101e6ca80d4Stron const char *myname = "pass_trigger";
102e6ca80d4Stron int pass_fd[2];
103e6ca80d4Stron struct pass_trigger *pp;
104e6ca80d4Stron int connect_fd;
105e6ca80d4Stron
106e6ca80d4Stron if (msg_verbose > 1)
107e6ca80d4Stron msg_info("%s: service %s", myname, service);
108e6ca80d4Stron
109e6ca80d4Stron /*
110e6ca80d4Stron * Connect...
111e6ca80d4Stron */
112e6ca80d4Stron if ((connect_fd = LOCAL_CONNECT(service, BLOCKING, timeout)) < 0) {
113e6ca80d4Stron if (msg_verbose)
114e6ca80d4Stron msg_warn("%s: connect to %s: %m", myname, service);
115e6ca80d4Stron return (-1);
116e6ca80d4Stron }
117e6ca80d4Stron close_on_exec(connect_fd, CLOSE_ON_EXEC);
118e6ca80d4Stron
119e6ca80d4Stron /*
120e6ca80d4Stron * Create a pipe, and send one pipe end to the server.
121e6ca80d4Stron */
122e6ca80d4Stron if (pipe(pass_fd) < 0)
123e6ca80d4Stron msg_fatal("%s: pipe: %m", myname);
124e6ca80d4Stron close_on_exec(pass_fd[0], CLOSE_ON_EXEC);
125e6ca80d4Stron close_on_exec(pass_fd[1], CLOSE_ON_EXEC);
126e6ca80d4Stron if (LOCAL_SEND_FD(connect_fd, pass_fd[0]) < 0)
127e6ca80d4Stron msg_fatal("%s: send file descriptor: %m", myname);
128e6ca80d4Stron
129e6ca80d4Stron /*
130e6ca80d4Stron * Stash away context.
131e6ca80d4Stron */
132e6ca80d4Stron pp = (struct pass_trigger *) mymalloc(sizeof(*pp));
133e6ca80d4Stron pp->connect_fd = connect_fd;
134e6ca80d4Stron pp->service = mystrdup(service);
135e6ca80d4Stron pp->pass_fd[0] = pass_fd[0];
136e6ca80d4Stron pp->pass_fd[1] = pass_fd[1];
137e6ca80d4Stron
138e6ca80d4Stron /*
139e6ca80d4Stron * Write the request...
140e6ca80d4Stron */
141e6ca80d4Stron if (write_buf(pass_fd[1], buf, len, timeout) < 0
142e6ca80d4Stron || write_buf(pass_fd[1], "", 1, timeout) < 0)
143e6ca80d4Stron if (msg_verbose)
144e6ca80d4Stron msg_warn("%s: write to %s: %m", myname, service);
145e6ca80d4Stron
146e6ca80d4Stron /*
147e6ca80d4Stron * Wakeup when the peer disconnects, or when we lose patience.
148e6ca80d4Stron */
149e6ca80d4Stron if (timeout > 0)
150e262b48eSchristos event_request_timer(pass_trigger_event, (void *) pp, timeout + 100);
151e262b48eSchristos event_enable_read(connect_fd, pass_trigger_event, (void *) pp);
152e6ca80d4Stron return (0);
153e6ca80d4Stron }
154