1/* $OpenBSD: proc.c,v 1.24 2024/02/13 08:10:23 nicm Exp $ */
2
3/*
4 * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/queue.h>
21#include <sys/socket.h>
22#include <sys/uio.h>
23#include <sys/utsname.h>
24
25#include <errno.h>
26#include <event.h>
27#include <imsg.h>
28#include <signal.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "tmux.h"
34
35struct tmuxproc {
36	const char	 *name;
37	int		  exit;
38
39	void		(*signalcb)(int);
40
41	struct event	  ev_sigint;
42	struct event	  ev_sighup;
43	struct event	  ev_sigchld;
44	struct event	  ev_sigcont;
45	struct event	  ev_sigterm;
46	struct event	  ev_sigusr1;
47	struct event	  ev_sigusr2;
48	struct event	  ev_sigwinch;
49
50	TAILQ_HEAD(, tmuxpeer) peers;
51};
52
53struct tmuxpeer {
54	struct tmuxproc	*parent;
55
56	struct imsgbuf	 ibuf;
57	struct event	 event;
58	uid_t		 uid;
59
60	int		 flags;
61#define PEER_BAD 0x1
62
63	void		(*dispatchcb)(struct imsg *, void *);
64	void		 *arg;
65
66	TAILQ_ENTRY(tmuxpeer) entry;
67};
68
69static int	peer_check_version(struct tmuxpeer *, struct imsg *);
70static void	proc_update_event(struct tmuxpeer *);
71
72static void
73proc_event_cb(__unused int fd, short events, void *arg)
74{
75	struct tmuxpeer	*peer = arg;
76	ssize_t		 n;
77	struct imsg	 imsg;
78
79	if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
80		if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
81		    n == 0) {
82			peer->dispatchcb(NULL, peer->arg);
83			return;
84		}
85		for (;;) {
86			if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
87				peer->dispatchcb(NULL, peer->arg);
88				return;
89			}
90			if (n == 0)
91				break;
92			log_debug("peer %p message %d", peer, imsg.hdr.type);
93
94			if (peer_check_version(peer, &imsg) != 0) {
95				fd = imsg_get_fd(&imsg);
96				if (fd != -1)
97					close(fd);
98				imsg_free(&imsg);
99				break;
100			}
101
102			peer->dispatchcb(&imsg, peer->arg);
103			imsg_free(&imsg);
104		}
105	}
106
107	if (events & EV_WRITE) {
108		if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
109			peer->dispatchcb(NULL, peer->arg);
110			return;
111		}
112	}
113
114	if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
115		peer->dispatchcb(NULL, peer->arg);
116		return;
117	}
118
119	proc_update_event(peer);
120}
121
122static void
123proc_signal_cb(int signo, __unused short events, void *arg)
124{
125	struct tmuxproc	*tp = arg;
126
127	tp->signalcb(signo);
128}
129
130static int
131peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
132{
133	int	version;
134
135	version = imsg->hdr.peerid & 0xff;
136	if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
137		log_debug("peer %p bad version %d", peer, version);
138
139		proc_send(peer, MSG_VERSION, -1, NULL, 0);
140		peer->flags |= PEER_BAD;
141
142		return (-1);
143	}
144	return (0);
145}
146
147static void
148proc_update_event(struct tmuxpeer *peer)
149{
150	short	events;
151
152	event_del(&peer->event);
153
154	events = EV_READ;
155	if (peer->ibuf.w.queued > 0)
156		events |= EV_WRITE;
157	event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
158
159	event_add(&peer->event, NULL);
160}
161
162int
163proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
164    size_t len)
165{
166	struct imsgbuf	*ibuf = &peer->ibuf;
167	void		*vp = (void *)buf;
168	int		 retval;
169
170	if (peer->flags & PEER_BAD)
171		return (-1);
172	log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
173
174	retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
175	if (retval != 1)
176		return (-1);
177	proc_update_event(peer);
178	return (0);
179}
180
181struct tmuxproc *
182proc_start(const char *name)
183{
184	struct tmuxproc	*tp;
185	struct utsname	 u;
186
187	log_open(name);
188	setproctitle("%s (%s)", name, socket_path);
189
190	if (uname(&u) < 0)
191		memset(&u, 0, sizeof u);
192
193	log_debug("%s started (%ld): version %s, socket %s, protocol %d", name,
194	    (long)getpid(), getversion(), socket_path, PROTOCOL_VERSION);
195	log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
196	    u.version, event_get_version(), event_get_method());
197
198	tp = xcalloc(1, sizeof *tp);
199	tp->name = xstrdup(name);
200	TAILQ_INIT(&tp->peers);
201
202	return (tp);
203}
204
205void
206proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
207{
208	log_debug("%s loop enter", tp->name);
209	do
210		event_loop(EVLOOP_ONCE);
211	while (!tp->exit && (loopcb == NULL || !loopcb ()));
212	log_debug("%s loop exit", tp->name);
213}
214
215void
216proc_exit(struct tmuxproc *tp)
217{
218	struct tmuxpeer	*peer;
219
220	TAILQ_FOREACH(peer, &tp->peers, entry)
221	    imsg_flush(&peer->ibuf);
222	tp->exit = 1;
223}
224
225void
226proc_set_signals(struct tmuxproc *tp, void (*signalcb)(int))
227{
228	struct sigaction	sa;
229
230	tp->signalcb = signalcb;
231
232	memset(&sa, 0, sizeof sa);
233	sigemptyset(&sa.sa_mask);
234	sa.sa_flags = SA_RESTART;
235	sa.sa_handler = SIG_IGN;
236
237	sigaction(SIGPIPE, &sa, NULL);
238	sigaction(SIGTSTP, &sa, NULL);
239	sigaction(SIGTTIN, &sa, NULL);
240	sigaction(SIGTTOU, &sa, NULL);
241	sigaction(SIGQUIT, &sa, NULL);
242
243	signal_set(&tp->ev_sigint, SIGINT, proc_signal_cb, tp);
244	signal_add(&tp->ev_sigint, NULL);
245	signal_set(&tp->ev_sighup, SIGHUP, proc_signal_cb, tp);
246	signal_add(&tp->ev_sighup, NULL);
247	signal_set(&tp->ev_sigchld, SIGCHLD, proc_signal_cb, tp);
248	signal_add(&tp->ev_sigchld, NULL);
249	signal_set(&tp->ev_sigcont, SIGCONT, proc_signal_cb, tp);
250	signal_add(&tp->ev_sigcont, NULL);
251	signal_set(&tp->ev_sigterm, SIGTERM, proc_signal_cb, tp);
252	signal_add(&tp->ev_sigterm, NULL);
253	signal_set(&tp->ev_sigusr1, SIGUSR1, proc_signal_cb, tp);
254	signal_add(&tp->ev_sigusr1, NULL);
255	signal_set(&tp->ev_sigusr2, SIGUSR2, proc_signal_cb, tp);
256	signal_add(&tp->ev_sigusr2, NULL);
257	signal_set(&tp->ev_sigwinch, SIGWINCH, proc_signal_cb, tp);
258	signal_add(&tp->ev_sigwinch, NULL);
259}
260
261void
262proc_clear_signals(struct tmuxproc *tp, int defaults)
263{
264	struct sigaction	sa;
265
266	memset(&sa, 0, sizeof sa);
267	sigemptyset(&sa.sa_mask);
268	sa.sa_flags = SA_RESTART;
269	sa.sa_handler = SIG_DFL;
270
271	sigaction(SIGPIPE, &sa, NULL);
272	sigaction(SIGTSTP, &sa, NULL);
273
274	signal_del(&tp->ev_sigint);
275	signal_del(&tp->ev_sighup);
276	signal_del(&tp->ev_sigchld);
277	signal_del(&tp->ev_sigcont);
278	signal_del(&tp->ev_sigterm);
279	signal_del(&tp->ev_sigusr1);
280	signal_del(&tp->ev_sigusr2);
281	signal_del(&tp->ev_sigwinch);
282
283	if (defaults) {
284		sigaction(SIGINT, &sa, NULL);
285		sigaction(SIGQUIT, &sa, NULL);
286		sigaction(SIGHUP, &sa, NULL);
287		sigaction(SIGCHLD, &sa, NULL);
288		sigaction(SIGCONT, &sa, NULL);
289		sigaction(SIGTERM, &sa, NULL);
290		sigaction(SIGUSR1, &sa, NULL);
291		sigaction(SIGUSR2, &sa, NULL);
292		sigaction(SIGWINCH, &sa, NULL);
293	}
294}
295
296struct tmuxpeer *
297proc_add_peer(struct tmuxproc *tp, int fd,
298    void (*dispatchcb)(struct imsg *, void *), void *arg)
299{
300	struct tmuxpeer	*peer;
301	gid_t		 gid;
302
303	peer = xcalloc(1, sizeof *peer);
304	peer->parent = tp;
305
306	peer->dispatchcb = dispatchcb;
307	peer->arg = arg;
308
309	imsg_init(&peer->ibuf, fd);
310	event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
311
312	if (getpeereid(fd, &peer->uid, &gid) != 0)
313		peer->uid = (uid_t)-1;
314
315	log_debug("add peer %p: %d (%p)", peer, fd, arg);
316	TAILQ_INSERT_TAIL(&tp->peers, peer, entry);
317
318	proc_update_event(peer);
319	return (peer);
320}
321
322void
323proc_remove_peer(struct tmuxpeer *peer)
324{
325	TAILQ_REMOVE(&peer->parent->peers, peer, entry);
326	log_debug("remove peer %p", peer);
327
328	event_del(&peer->event);
329	imsg_clear(&peer->ibuf);
330
331	close(peer->ibuf.fd);
332	free(peer);
333}
334
335void
336proc_kill_peer(struct tmuxpeer *peer)
337{
338	peer->flags |= PEER_BAD;
339}
340
341void
342proc_flush_peer(struct tmuxpeer *peer)
343{
344	imsg_flush(&peer->ibuf);
345}
346
347void
348proc_toggle_log(struct tmuxproc *tp)
349{
350	log_toggle(tp->name);
351}
352
353pid_t
354proc_fork_and_daemon(int *fd)
355{
356	pid_t	pid;
357	int	pair[2];
358
359	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
360		fatal("socketpair failed");
361	switch (pid = fork()) {
362	case -1:
363		fatal("fork failed");
364	case 0:
365		close(pair[0]);
366		*fd = pair[1];
367		if (daemon(1, 0) != 0)
368			fatal("daemon failed");
369		return (0);
370	default:
371		close(pair[1]);
372		*fd = pair[0];
373		return (pid);
374	}
375}
376
377uid_t
378proc_get_peer_uid(struct tmuxpeer *peer)
379{
380	return (peer->uid);
381}
382