1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/types.h>
31#include <sys/capsicum.h>
32#include <sys/file.h>
33#include <sys/stat.h>
34
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <libgen.h>
39#include <libutil.h>
40#include <signal.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <time.h>
45#include <unistd.h>
46
47struct pidfh {
48	int	pf_dirfd;
49	int	pf_fd;
50	char	pf_dir[MAXPATHLEN + 1];
51	char	pf_filename[MAXPATHLEN + 1];
52	dev_t	pf_dev;
53	ino_t	pf_ino;
54};
55
56static int _pidfile_remove(struct pidfh *pfh, int freeit);
57
58static int
59pidfile_verify(const struct pidfh *pfh)
60{
61	struct stat sb;
62
63	if (pfh == NULL || pfh->pf_fd == -1)
64		return (EDOOFUS);
65	/*
66	 * Check remembered descriptor.
67	 */
68	if (fstat(pfh->pf_fd, &sb) == -1)
69		return (errno);
70	if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
71		return (EDOOFUS);
72	return (0);
73}
74
75static int
76pidfile_read_impl(int dirfd, const char *filename, pid_t *pidptr)
77{
78	char buf[16], *endptr;
79	int error, fd, i;
80
81	fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
82	if (fd == -1)
83		return (errno);
84
85	i = read(fd, buf, sizeof(buf) - 1);
86	error = errno;	/* Remember errno in case close() wants to change it. */
87	close(fd);
88	if (i == -1)
89		return (error);
90	else if (i == 0)
91		return (EAGAIN);
92	buf[i] = '\0';
93
94	*pidptr = strtol(buf, &endptr, 10);
95	if (endptr != &buf[i])
96		return (EINVAL);
97
98	return (0);
99}
100
101static int
102pidfile_read(int dirfd, const char *filename, pid_t *pidptr)
103{
104	struct timespec rqtp;
105	int count;
106
107	count = 20;
108	rqtp.tv_sec = 0;
109	rqtp.tv_nsec = 5000000;
110	for (;;) {
111		errno = pidfile_read_impl(dirfd, filename, pidptr);
112		if (errno != EAGAIN || --count == 0)
113			break;
114		nanosleep(&rqtp, 0);
115	}
116	if (errno == EAGAIN)
117		*pidptr = -1;
118	return (errno);
119}
120
121struct pidfh *
122pidfile_open(const char *pathp, mode_t mode, pid_t *pidptr)
123{
124	char path[MAXPATHLEN];
125	struct pidfh *pfh;
126	struct stat sb;
127	int error, fd, dirfd, dirlen, filenamelen;
128	cap_rights_t caprights;
129
130	pfh = malloc(sizeof(*pfh));
131	if (pfh == NULL)
132		return (NULL);
133
134	if (pathp == NULL) {
135		dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
136		    "/var/run/");
137		filenamelen = snprintf(pfh->pf_filename,
138		    sizeof(pfh->pf_filename), "%s.pid", getprogname());
139	} else {
140		if (strlcpy(path, pathp, sizeof(path)) >= sizeof(path)) {
141			free(pfh);
142			errno = ENAMETOOLONG;
143			return (NULL);
144		}
145		dirlen = strlcpy(pfh->pf_dir, dirname(path),
146		    sizeof(pfh->pf_dir));
147		(void)strlcpy(path, pathp, sizeof(path));
148		filenamelen = strlcpy(pfh->pf_filename, basename(path),
149		    sizeof(pfh->pf_filename));
150	}
151
152	if (dirlen >= (int)sizeof(pfh->pf_dir) ||
153	    filenamelen >= (int)sizeof(pfh->pf_filename)) {
154		free(pfh);
155		errno = ENAMETOOLONG;
156		return (NULL);
157	}
158
159	dirfd = open(pfh->pf_dir, O_CLOEXEC | O_DIRECTORY | O_NONBLOCK);
160	if (dirfd == -1) {
161		error = errno;
162		free(pfh);
163		errno = error;
164		return (NULL);
165	}
166
167	/*
168	 * Open the PID file and obtain exclusive lock.
169	 * We truncate PID file here only to remove old PID immediately,
170	 * PID file will be truncated again in pidfile_write(), so
171	 * pidfile_write() can be called multiple times.
172	 */
173	fd = flopenat(dirfd, pfh->pf_filename,
174	    O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
175	if (fd == -1) {
176		if (errno == EWOULDBLOCK) {
177			if (pidptr == NULL) {
178				errno = EEXIST;
179			} else {
180				errno = pidfile_read(dirfd,
181				    pfh->pf_filename, pidptr);
182				if (errno == 0 || errno == EAGAIN)
183					errno = EEXIST;
184			}
185		}
186		error = errno;
187		close(dirfd);
188		free(pfh);
189		errno = error;
190		return (NULL);
191	}
192
193	/*
194	 * Remember file information, so in pidfile_write() we are sure we write
195	 * to the proper descriptor.
196	 */
197	if (fstat(fd, &sb) == -1) {
198		goto failed;
199	}
200
201	if (cap_rights_limit(dirfd,
202	    cap_rights_init(&caprights, CAP_UNLINKAT)) < 0 && errno != ENOSYS) {
203		goto failed;
204	}
205
206	if (cap_rights_limit(fd, cap_rights_init(&caprights, CAP_PWRITE,
207	    CAP_FSTAT, CAP_FTRUNCATE, CAP_EVENT)) < 0 &&
208	    errno != ENOSYS) {
209		goto failed;
210	}
211
212	pfh->pf_dirfd = dirfd;
213	pfh->pf_fd = fd;
214	pfh->pf_dev = sb.st_dev;
215	pfh->pf_ino = sb.st_ino;
216
217	return (pfh);
218
219failed:
220	error = errno;
221	unlinkat(dirfd, pfh->pf_filename, 0);
222	close(dirfd);
223	close(fd);
224	free(pfh);
225	errno = error;
226	return (NULL);
227}
228
229int
230pidfile_write(struct pidfh *pfh)
231{
232	char pidstr[16];
233	int error, fd;
234
235	/*
236	 * Check remembered descriptor, so we don't overwrite some other
237	 * file if pidfile was closed and descriptor reused.
238	 */
239	errno = pidfile_verify(pfh);
240	if (errno != 0) {
241		/*
242		 * Don't close descriptor, because we are not sure if it's ours.
243		 */
244		return (-1);
245	}
246	fd = pfh->pf_fd;
247
248	/*
249	 * Truncate PID file, so multiple calls of pidfile_write() are allowed.
250	 */
251	if (ftruncate(fd, 0) == -1) {
252		error = errno;
253		_pidfile_remove(pfh, 0);
254		errno = error;
255		return (-1);
256	}
257
258	snprintf(pidstr, sizeof(pidstr), "%u", getpid());
259	if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
260		error = errno;
261		_pidfile_remove(pfh, 0);
262		errno = error;
263		return (-1);
264	}
265
266	return (0);
267}
268
269int
270pidfile_close(struct pidfh *pfh)
271{
272	int error;
273
274	error = pidfile_verify(pfh);
275	if (error != 0) {
276		errno = error;
277		return (-1);
278	}
279
280	if (close(pfh->pf_fd) == -1)
281		error = errno;
282	if (close(pfh->pf_dirfd) == -1 && error == 0)
283		error = errno;
284
285	free(pfh);
286	if (error != 0) {
287		errno = error;
288		return (-1);
289	}
290	return (0);
291}
292
293static int
294_pidfile_remove(struct pidfh *pfh, int freeit)
295{
296	int error;
297
298	error = pidfile_verify(pfh);
299	if (error != 0) {
300		errno = error;
301		return (-1);
302	}
303
304	if (funlinkat(pfh->pf_dirfd, pfh->pf_filename, pfh->pf_fd, 0) == -1) {
305		if (errno == EDEADLK)
306			return (-1);
307		error = errno;
308	}
309	if (close(pfh->pf_fd) == -1 && error == 0)
310		error = errno;
311	if (close(pfh->pf_dirfd) == -1 && error == 0)
312		error = errno;
313	if (freeit)
314		free(pfh);
315	else
316		pfh->pf_fd = -1;
317	if (error != 0) {
318		errno = error;
319		return (-1);
320	}
321	return (0);
322}
323
324int
325pidfile_remove(struct pidfh *pfh)
326{
327
328	return (_pidfile_remove(pfh, 1));
329}
330
331int
332pidfile_fileno(const struct pidfh *pfh)
333{
334
335	if (pfh == NULL || pfh->pf_fd == -1) {
336		errno = EDOOFUS;
337		return (-1);
338	}
339	return (pfh->pf_fd);
340}
341
342int
343pidfile_signal(const char *pathp, int sig, pid_t *pidptr)
344{
345	pid_t pid;
346	int fd;
347
348	fd = flopenat(AT_FDCWD, pathp,
349	    O_RDONLY | O_CLOEXEC | O_NONBLOCK);
350	if (fd >= 0) {
351		/*
352		 * The file exists but is not locked,
353		 * so the daemon is dead. Nothing to do.
354		 */
355		close(fd);
356		errno = ENOENT;
357		return (errno);
358	}
359	if (errno != EWOULDBLOCK) {
360		return (errno);
361	}
362	errno = pidfile_read(AT_FDCWD, pathp, &pid);
363	if (errno != 0)
364		return (errno);
365	/*
366	 * Refuse to send broadcast or group signals, this has
367	 * happened due to the bugs in pidfile(3).
368	 */
369	if (pid <= 0)
370		return (EDOM);
371	kill(pid, sig);
372	if (pidptr != NULL)
373		*pidptr = pid;
374	return (errno);
375}
376