1/*
2 * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>.
3 * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
4 *
5 * This code is derived from software contributed to The DragonFly Project
6 * by Simon Schubert <2@0x2c.org>.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 *    contributors may be used to endorse or promote products derived
20 *    from this software without specific, prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/param.h>
37#include <sys/file.h>
38
39#include <ctype.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <netdb.h>
43#include <pwd.h>
44#include <setjmp.h>
45#include <signal.h>
46#include <stdio.h>
47#include <string.h>
48#include <syslog.h>
49#include <unistd.h>
50
51#include "dma.h"
52
53const char *
54hostname(void)
55{
56#ifndef HOST_NAME_MAX
57#define HOST_NAME_MAX	255
58#endif
59	static char name[HOST_NAME_MAX+1];
60	static int initialized = 0;
61	char *s;
62
63	if (initialized)
64		return (name);
65
66	if (config.mailname == NULL || !*config.mailname)
67		goto local;
68
69	if (config.mailname[0] == '/') {
70		/*
71		 * If the mailname looks like an absolute path,
72		 * treat it as a file.
73		 */
74		FILE *fp;
75
76		fp = fopen(config.mailname, "r");
77		if (fp == NULL)
78			goto local;
79
80		s = fgets(name, sizeof(name), fp);
81		fclose(fp);
82		if (s == NULL)
83			goto local;
84
85		for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
86			/* NOTHING */;
87		*s = 0;
88
89		if (!*name)
90			goto local;
91
92		initialized = 1;
93		return (name);
94	} else {
95		snprintf(name, sizeof(name), "%s", config.mailname);
96		initialized = 1;
97		return (name);
98	}
99
100local:
101	if (gethostname(name, sizeof(name)) != 0)
102		*name = 0;
103	/*
104	 * gethostname() is allowed to truncate name without NUL-termination
105	 * and at the same time not return an error.
106	 */
107	name[sizeof(name) - 1] = 0;
108
109	for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
110		/* NOTHING */;
111	*s = 0;
112
113	if (!*name)
114		snprintf(name, sizeof(name), "unknown-hostname");
115
116	initialized = 1;
117	return (name);
118}
119
120void
121setlogident(const char *fmt, ...)
122{
123	static char tag[50];
124
125	snprintf(tag, sizeof(tag), "%s", logident_base);
126	if (fmt != NULL) {
127		va_list ap;
128		char sufx[50];
129
130		va_start(ap, fmt);
131		vsnprintf(sufx, sizeof(sufx), fmt, ap);
132		va_end(ap);
133		snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx);
134	}
135	closelog();
136	openlog(tag, 0, LOG_MAIL);
137}
138
139void
140errlog(int exitcode, const char *fmt, ...)
141{
142	int oerrno = errno;
143	va_list ap;
144	char outs[ERRMSG_SIZE];
145
146	outs[0] = 0;
147	if (fmt != NULL) {
148		va_start(ap, fmt);
149		vsnprintf(outs, sizeof(outs), fmt, ap);
150		va_end(ap);
151	}
152
153	errno = oerrno;
154	if (*outs != 0) {
155		syslog(LOG_ERR, "%s: %m", outs);
156		fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno));
157	} else {
158		syslog(LOG_ERR, "%m");
159		fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno));
160	}
161
162	exit(exitcode);
163}
164
165void
166errlogx(int exitcode, const char *fmt, ...)
167{
168	va_list ap;
169	char outs[ERRMSG_SIZE];
170
171	outs[0] = 0;
172	if (fmt != NULL) {
173		va_start(ap, fmt);
174		vsnprintf(outs, sizeof(outs), fmt, ap);
175		va_end(ap);
176	}
177
178	if (*outs != 0) {
179		syslog(LOG_ERR, "%s", outs);
180		fprintf(stderr, "%s: %s\n", getprogname(), outs);
181	} else {
182		syslog(LOG_ERR, "Unknown error");
183		fprintf(stderr, "%s: Unknown error\n", getprogname());
184	}
185
186	exit(exitcode);
187}
188
189static int
190check_username(const char *name, uid_t ckuid)
191{
192	struct passwd *pwd;
193
194	if (name == NULL)
195		return (0);
196	pwd = getpwnam(name);
197	if (pwd == NULL || pwd->pw_uid != ckuid)
198		return (0);
199	snprintf(username, sizeof(username), "%s", name);
200	return (1);
201}
202
203void
204set_username(void)
205{
206	struct passwd *pwd;
207
208	useruid = getuid();
209	if (check_username(getlogin(), useruid))
210		return;
211	if (check_username(getenv("LOGNAME"), useruid))
212		return;
213	if (check_username(getenv("USER"), useruid))
214		return;
215	pwd = getpwuid(useruid);
216	if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') {
217		if (check_username(pwd->pw_name, useruid))
218			return;
219	}
220	snprintf(username, sizeof(username), "uid=%ld", (long)useruid);
221}
222
223void
224deltmp(void)
225{
226	struct stritem *t;
227
228	SLIST_FOREACH(t, &tmpfs, next) {
229		unlink(t->str);
230	}
231}
232
233static sigjmp_buf sigbuf;
234static int sigbuf_valid;
235
236static void
237sigalrm_handler(int signo)
238{
239	(void)signo;	/* so that gcc doesn't complain */
240	if (sigbuf_valid)
241		siglongjmp(sigbuf, 1);
242}
243
244int
245do_timeout(int timeout, int dojmp)
246{
247	struct sigaction act;
248	int ret = 0;
249
250	sigemptyset(&act.sa_mask);
251	act.sa_flags = 0;
252
253	if (timeout) {
254		act.sa_handler = sigalrm_handler;
255		if (sigaction(SIGALRM, &act, NULL) != 0)
256			syslog(LOG_WARNING, "can not set signal handler: %m");
257		if (dojmp) {
258			ret = sigsetjmp(sigbuf, 1);
259			if (ret)
260				goto disable;
261			/* else just programmed */
262			sigbuf_valid = 1;
263		}
264
265		alarm(timeout);
266	} else {
267disable:
268		alarm(0);
269
270		act.sa_handler = SIG_IGN;
271		if (sigaction(SIGALRM, &act, NULL) != 0)
272			syslog(LOG_WARNING, "can not remove signal handler: %m");
273		sigbuf_valid = 0;
274	}
275
276	return (ret);
277}
278
279int
280open_locked(const char *fname, int flags, ...)
281{
282	int mode = 0;
283
284	if (flags & O_CREAT) {
285		va_list ap;
286		va_start(ap, flags);
287		mode = va_arg(ap, int);
288		va_end(ap);
289	}
290
291#ifndef O_EXLOCK
292	int fd, save_errno;
293
294	fd = open(fname, flags, mode);
295	if (fd < 0)
296		return(fd);
297	if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
298		save_errno = errno;
299		close(fd);
300		errno = save_errno;
301		return(-1);
302	}
303	return(fd);
304#else
305	return(open(fname, flags|O_EXLOCK, mode));
306#endif
307}
308
309char *
310rfc822date(void)
311{
312	static char str[50];
313	size_t error;
314	time_t now;
315
316	now = time(NULL);
317	error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
318		       localtime(&now));
319	if (error == 0)
320		strcpy(str, "(date fail)");
321	return (str);
322}
323
324int
325strprefixcmp(const char *str, const char *prefix)
326{
327	return (strncasecmp(str, prefix, strlen(prefix)));
328}
329
330void
331init_random(void)
332{
333	unsigned int seed;
334	int rf;
335
336	rf = open("/dev/urandom", O_RDONLY);
337	if (rf == -1)
338		rf = open("/dev/random", O_RDONLY);
339
340	if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed)))
341		seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed;
342
343	srandom(seed);
344
345	if (rf != -1)
346		close(rf);
347}
348