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 <strings.h>
48#include <string.h>
49#include <syslog.h>
50#include <unistd.h>
51
52#include "dma.h"
53
54const char *
55hostname(void)
56{
57#ifndef HOST_NAME_MAX
58#define HOST_NAME_MAX	255
59#endif
60	static char name[HOST_NAME_MAX+1];
61	static int initialized = 0;
62	char *s;
63
64	if (initialized)
65		return (name);
66
67	if (config.mailname == NULL || !*config.mailname)
68		goto local;
69
70	if (config.mailname[0] == '/') {
71		/*
72		 * If the mailname looks like an absolute path,
73		 * treat it as a file.
74		 */
75		FILE *fp;
76
77		fp = fopen(config.mailname, "r");
78		if (fp == NULL)
79			goto local;
80
81		s = fgets(name, sizeof(name), fp);
82		fclose(fp);
83		if (s == NULL)
84			goto local;
85
86		for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
87			/* NOTHING */;
88		*s = 0;
89
90		if (!*name)
91			goto local;
92
93		initialized = 1;
94		return (name);
95	} else {
96		snprintf(name, sizeof(name), "%s", config.mailname);
97		initialized = 1;
98		return (name);
99	}
100
101local:
102	snprintf(name, sizeof(name), "%s", systemhostname());
103
104	initialized = 1;
105	return (name);
106}
107
108const char *
109systemhostname(void)
110{
111#ifndef HOST_NAME_MAX
112#define HOST_NAME_MAX	255
113#endif
114	static char name[HOST_NAME_MAX+1];
115	static int initialized = 0;
116	char *s;
117
118	if (initialized)
119		return (name);
120
121	if (gethostname(name, sizeof(name)) != 0)
122		*name = 0;
123	/*
124	 * gethostname() is allowed to truncate name without NUL-termination
125	 * and at the same time not return an error.
126	 */
127	name[sizeof(name) - 1] = 0;
128
129	for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
130		/* NOTHING */;
131	*s = 0;
132
133	if (!*name)
134		snprintf(name, sizeof(name), "unknown-hostname");
135
136	initialized = 1;
137	return (name);
138}
139
140void
141setlogident(const char *fmt, ...)
142{
143	static char tag[50];
144
145	snprintf(tag, sizeof(tag), "%s", logident_base);
146	if (fmt != NULL) {
147		va_list ap;
148		char sufx[50];
149
150		va_start(ap, fmt);
151		vsnprintf(sufx, sizeof(sufx), fmt, ap);
152		va_end(ap);
153		snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx);
154	}
155	closelog();
156	openlog(tag, 0, LOG_MAIL);
157}
158
159void
160errlog(int exitcode, const char *fmt, ...)
161{
162	int oerrno = errno;
163	va_list ap;
164	char outs[ERRMSG_SIZE];
165
166	outs[0] = 0;
167	if (fmt != NULL) {
168		va_start(ap, fmt);
169		vsnprintf(outs, sizeof(outs), fmt, ap);
170		va_end(ap);
171	}
172
173	errno = oerrno;
174	if (*outs != 0) {
175		syslog(LOG_ERR, "%s: %m", outs);
176		fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno));
177	} else {
178		syslog(LOG_ERR, "%m");
179		fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno));
180	}
181
182	exit(exitcode);
183}
184
185void
186errlogx(int exitcode, const char *fmt, ...)
187{
188	va_list ap;
189	char outs[ERRMSG_SIZE];
190
191	outs[0] = 0;
192	if (fmt != NULL) {
193		va_start(ap, fmt);
194		vsnprintf(outs, sizeof(outs), fmt, ap);
195		va_end(ap);
196	}
197
198	if (*outs != 0) {
199		syslog(LOG_ERR, "%s", outs);
200		fprintf(stderr, "%s: %s\n", getprogname(), outs);
201	} else {
202		syslog(LOG_ERR, "Unknown error");
203		fprintf(stderr, "%s: Unknown error\n", getprogname());
204	}
205
206	exit(exitcode);
207}
208
209static int
210check_username(const char *name, uid_t ckuid)
211{
212	struct passwd *pwd;
213
214	if (name == NULL)
215		return (0);
216	pwd = getpwnam(name);
217	if (pwd == NULL || pwd->pw_uid != ckuid)
218		return (0);
219	snprintf(username, sizeof(username), "%s", name);
220	return (1);
221}
222
223void
224set_username(void)
225{
226	struct passwd *pwd;
227
228	useruid = getuid();
229	if (check_username(getlogin(), useruid))
230		return;
231	if (check_username(getenv("LOGNAME"), useruid))
232		return;
233	if (check_username(getenv("USER"), useruid))
234		return;
235	pwd = getpwuid(useruid);
236	if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') {
237		if (check_username(pwd->pw_name, useruid))
238			return;
239	}
240	snprintf(username, sizeof(username), "uid=%ld", (long)useruid);
241}
242
243void
244deltmp(void)
245{
246	struct stritem *t;
247
248	SLIST_FOREACH(t, &tmpfs, next) {
249		unlink(t->str);
250	}
251}
252
253static sigjmp_buf sigbuf;
254static int sigbuf_valid;
255
256static void
257sigalrm_handler(int signo)
258{
259	(void)signo;	/* so that gcc doesn't complain */
260	if (sigbuf_valid)
261		siglongjmp(sigbuf, 1);
262}
263
264int
265do_timeout(int timeout, int dojmp)
266{
267	struct sigaction act;
268	int ret = 0;
269
270	sigemptyset(&act.sa_mask);
271	act.sa_flags = 0;
272
273	if (timeout) {
274		act.sa_handler = sigalrm_handler;
275		if (sigaction(SIGALRM, &act, NULL) != 0)
276			syslog(LOG_WARNING, "can not set signal handler: %m");
277		if (dojmp) {
278			ret = sigsetjmp(sigbuf, 1);
279			if (ret)
280				goto disable;
281			/* else just programmed */
282			sigbuf_valid = 1;
283		}
284
285		alarm(timeout);
286	} else {
287disable:
288		alarm(0);
289
290		act.sa_handler = SIG_IGN;
291		if (sigaction(SIGALRM, &act, NULL) != 0)
292			syslog(LOG_WARNING, "can not remove signal handler: %m");
293		sigbuf_valid = 0;
294	}
295
296	return (ret);
297}
298
299int
300open_locked(const char *fname, int flags, ...)
301{
302	int mode = 0;
303
304	if (flags & O_CREAT) {
305		va_list ap;
306		va_start(ap, flags);
307		mode = va_arg(ap, int);
308		va_end(ap);
309	}
310
311#ifndef O_EXLOCK
312	int fd, save_errno;
313
314	fd = open(fname, flags, mode);
315	if (fd < 0)
316		return(fd);
317	if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
318		save_errno = errno;
319		close(fd);
320		errno = save_errno;
321		return(-1);
322	}
323	return(fd);
324#else
325	return(open(fname, flags|O_EXLOCK, mode));
326#endif
327}
328
329char *
330rfc822date(void)
331{
332	static char str[50];
333	size_t error;
334	time_t now;
335
336	now = time(NULL);
337	error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
338		       localtime(&now));
339	if (error == 0)
340		strcpy(str, "(date fail)");
341	return (str);
342}
343
344int
345strprefixcmp(const char *str, const char *prefix)
346{
347	return (strncasecmp(str, prefix, strlen(prefix)));
348}
349
350void
351init_random(void)
352{
353	unsigned int seed;
354	int rf;
355
356	rf = open("/dev/urandom", O_RDONLY);
357	if (rf == -1)
358		rf = open("/dev/random", O_RDONLY);
359
360	if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed)))
361		seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed;
362
363	srandom(seed);
364
365	if (rf != -1)
366		close(rf);
367}
368