11da0a9f2SSimon Schubert /*
237d59876SJohn Marino * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>.
31da0a9f2SSimon Schubert * Copyright (c) 2008 The DragonFly Project. All rights reserved.
41da0a9f2SSimon Schubert *
51da0a9f2SSimon Schubert * This code is derived from software contributed to The DragonFly Project
637d59876SJohn Marino * by Simon Schubert <2@0x2c.org>.
71da0a9f2SSimon Schubert *
81da0a9f2SSimon Schubert * Redistribution and use in source and binary forms, with or without
91da0a9f2SSimon Schubert * modification, are permitted provided that the following conditions
101da0a9f2SSimon Schubert * are met:
111da0a9f2SSimon Schubert *
121da0a9f2SSimon Schubert * 1. Redistributions of source code must retain the above copyright
131da0a9f2SSimon Schubert * notice, this list of conditions and the following disclaimer.
141da0a9f2SSimon Schubert * 2. Redistributions in binary form must reproduce the above copyright
151da0a9f2SSimon Schubert * notice, this list of conditions and the following disclaimer in
161da0a9f2SSimon Schubert * the documentation and/or other materials provided with the
171da0a9f2SSimon Schubert * distribution.
181da0a9f2SSimon Schubert * 3. Neither the name of The DragonFly Project nor the names of its
191da0a9f2SSimon Schubert * contributors may be used to endorse or promote products derived
201da0a9f2SSimon Schubert * from this software without specific, prior written permission.
211da0a9f2SSimon Schubert *
221da0a9f2SSimon Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
231da0a9f2SSimon Schubert * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
241da0a9f2SSimon Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
251da0a9f2SSimon Schubert * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
261da0a9f2SSimon Schubert * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
271da0a9f2SSimon Schubert * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
281da0a9f2SSimon Schubert * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
291da0a9f2SSimon Schubert * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
301da0a9f2SSimon Schubert * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
311da0a9f2SSimon Schubert * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
321da0a9f2SSimon Schubert * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331da0a9f2SSimon Schubert * SUCH DAMAGE.
341da0a9f2SSimon Schubert */
351da0a9f2SSimon Schubert
361da0a9f2SSimon Schubert #include <sys/param.h>
37c8b07ee5SSascha Wildner #include <sys/file.h>
38c8b07ee5SSascha Wildner
39c8b07ee5SSascha Wildner #include <ctype.h>
401da0a9f2SSimon Schubert #include <errno.h>
411da0a9f2SSimon Schubert #include <fcntl.h>
421da0a9f2SSimon Schubert #include <netdb.h>
431da0a9f2SSimon Schubert #include <pwd.h>
44c8b07ee5SSascha Wildner #include <setjmp.h>
45c8b07ee5SSascha Wildner #include <signal.h>
461da0a9f2SSimon Schubert #include <stdio.h>
4792fe556dSDaniel Fojt #include <strings.h>
4892fe556dSDaniel Fojt #include <string.h>
491da0a9f2SSimon Schubert #include <syslog.h>
501da0a9f2SSimon Schubert #include <unistd.h>
511da0a9f2SSimon Schubert
521da0a9f2SSimon Schubert #include "dma.h"
531da0a9f2SSimon Schubert
541da0a9f2SSimon Schubert const char *
hostname(void)551da0a9f2SSimon Schubert hostname(void)
561da0a9f2SSimon Schubert {
57c8b07ee5SSascha Wildner #ifndef HOST_NAME_MAX
58c8b07ee5SSascha Wildner #define HOST_NAME_MAX 255
59c8b07ee5SSascha Wildner #endif
60c8b07ee5SSascha Wildner static char name[HOST_NAME_MAX+1];
61c8b07ee5SSascha Wildner static int initialized = 0;
62c8b07ee5SSascha Wildner char *s;
631da0a9f2SSimon Schubert
641da0a9f2SSimon Schubert if (initialized)
651da0a9f2SSimon Schubert return (name);
661da0a9f2SSimon Schubert
67c8b07ee5SSascha Wildner if (config.mailname == NULL || !*config.mailname)
68c8b07ee5SSascha Wildner goto local;
69c8b07ee5SSascha Wildner
70c8b07ee5SSascha Wildner if (config.mailname[0] == '/') {
71c8b07ee5SSascha Wildner /*
72c8b07ee5SSascha Wildner * If the mailname looks like an absolute path,
73c8b07ee5SSascha Wildner * treat it as a file.
74c8b07ee5SSascha Wildner */
75c8b07ee5SSascha Wildner FILE *fp;
76c8b07ee5SSascha Wildner
77c8b07ee5SSascha Wildner fp = fopen(config.mailname, "r");
78c8b07ee5SSascha Wildner if (fp == NULL)
79c8b07ee5SSascha Wildner goto local;
80c8b07ee5SSascha Wildner
81c8b07ee5SSascha Wildner s = fgets(name, sizeof(name), fp);
82c8b07ee5SSascha Wildner fclose(fp);
83c8b07ee5SSascha Wildner if (s == NULL)
84c8b07ee5SSascha Wildner goto local;
85c8b07ee5SSascha Wildner
86c8b07ee5SSascha Wildner for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
87c8b07ee5SSascha Wildner /* NOTHING */;
88c8b07ee5SSascha Wildner *s = 0;
89c8b07ee5SSascha Wildner
90c8b07ee5SSascha Wildner if (!*name)
91c8b07ee5SSascha Wildner goto local;
92c8b07ee5SSascha Wildner
93c8b07ee5SSascha Wildner initialized = 1;
94c8b07ee5SSascha Wildner return (name);
95c8b07ee5SSascha Wildner } else {
96ca259d14SSimon Schubert snprintf(name, sizeof(name), "%s", config.mailname);
971da0a9f2SSimon Schubert initialized = 1;
981da0a9f2SSimon Schubert return (name);
991da0a9f2SSimon Schubert }
100c8b07ee5SSascha Wildner
101c8b07ee5SSascha Wildner local:
102*577b958fSDaniel Fojt snprintf(name, sizeof(name), "%s", systemhostname());
103*577b958fSDaniel Fojt
104*577b958fSDaniel Fojt initialized = 1;
105*577b958fSDaniel Fojt return (name);
106*577b958fSDaniel Fojt }
107*577b958fSDaniel Fojt
108*577b958fSDaniel Fojt const char *
systemhostname(void)109*577b958fSDaniel Fojt systemhostname(void)
110*577b958fSDaniel Fojt {
111*577b958fSDaniel Fojt #ifndef HOST_NAME_MAX
112*577b958fSDaniel Fojt #define HOST_NAME_MAX 255
113*577b958fSDaniel Fojt #endif
114*577b958fSDaniel Fojt static char name[HOST_NAME_MAX+1];
115*577b958fSDaniel Fojt static int initialized = 0;
116*577b958fSDaniel Fojt char *s;
117*577b958fSDaniel Fojt
118*577b958fSDaniel Fojt if (initialized)
119*577b958fSDaniel Fojt return (name);
120*577b958fSDaniel Fojt
121c8b07ee5SSascha Wildner if (gethostname(name, sizeof(name)) != 0)
122c8b07ee5SSascha Wildner *name = 0;
123c8b07ee5SSascha Wildner /*
124c8b07ee5SSascha Wildner * gethostname() is allowed to truncate name without NUL-termination
125c8b07ee5SSascha Wildner * and at the same time not return an error.
126c8b07ee5SSascha Wildner */
127c8b07ee5SSascha Wildner name[sizeof(name) - 1] = 0;
128c8b07ee5SSascha Wildner
129c8b07ee5SSascha Wildner for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
130c8b07ee5SSascha Wildner /* NOTHING */;
131c8b07ee5SSascha Wildner *s = 0;
132c8b07ee5SSascha Wildner
133c8b07ee5SSascha Wildner if (!*name)
134c8b07ee5SSascha Wildner snprintf(name, sizeof(name), "unknown-hostname");
135c8b07ee5SSascha Wildner
1361da0a9f2SSimon Schubert initialized = 1;
1371da0a9f2SSimon Schubert return (name);
1381da0a9f2SSimon Schubert }
1391da0a9f2SSimon Schubert
1401da0a9f2SSimon Schubert void
setlogident(const char * fmt,...)1411da0a9f2SSimon Schubert setlogident(const char *fmt, ...)
1421da0a9f2SSimon Schubert {
143c8b07ee5SSascha Wildner static char tag[50];
1441da0a9f2SSimon Schubert
145c8b07ee5SSascha Wildner snprintf(tag, sizeof(tag), "%s", logident_base);
1461da0a9f2SSimon Schubert if (fmt != NULL) {
1471da0a9f2SSimon Schubert va_list ap;
148c8b07ee5SSascha Wildner char sufx[50];
1491da0a9f2SSimon Schubert
1501da0a9f2SSimon Schubert va_start(ap, fmt);
151c8b07ee5SSascha Wildner vsnprintf(sufx, sizeof(sufx), fmt, ap);
1521da0a9f2SSimon Schubert va_end(ap);
153c8b07ee5SSascha Wildner snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx);
1541da0a9f2SSimon Schubert }
1551da0a9f2SSimon Schubert closelog();
156c8b07ee5SSascha Wildner openlog(tag, 0, LOG_MAIL);
1571da0a9f2SSimon Schubert }
1581da0a9f2SSimon Schubert
1591da0a9f2SSimon Schubert void
errlog(int exitcode,const char * fmt,...)1601da0a9f2SSimon Schubert errlog(int exitcode, const char *fmt, ...)
1611da0a9f2SSimon Schubert {
1621da0a9f2SSimon Schubert int oerrno = errno;
1631da0a9f2SSimon Schubert va_list ap;
164c8b07ee5SSascha Wildner char outs[ERRMSG_SIZE];
1651da0a9f2SSimon Schubert
166c8b07ee5SSascha Wildner outs[0] = 0;
1671da0a9f2SSimon Schubert if (fmt != NULL) {
1681da0a9f2SSimon Schubert va_start(ap, fmt);
169c8b07ee5SSascha Wildner vsnprintf(outs, sizeof(outs), fmt, ap);
1701da0a9f2SSimon Schubert va_end(ap);
1711da0a9f2SSimon Schubert }
1721da0a9f2SSimon Schubert
173c8b07ee5SSascha Wildner errno = oerrno;
174c8b07ee5SSascha Wildner if (*outs != 0) {
1751da0a9f2SSimon Schubert syslog(LOG_ERR, "%s: %m", outs);
1761da0a9f2SSimon Schubert fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno));
1771da0a9f2SSimon Schubert } else {
1781da0a9f2SSimon Schubert syslog(LOG_ERR, "%m");
1791da0a9f2SSimon Schubert fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno));
1801da0a9f2SSimon Schubert }
1811da0a9f2SSimon Schubert
1821da0a9f2SSimon Schubert exit(exitcode);
1831da0a9f2SSimon Schubert }
1841da0a9f2SSimon Schubert
1851da0a9f2SSimon Schubert void
errlogx(int exitcode,const char * fmt,...)1861da0a9f2SSimon Schubert errlogx(int exitcode, const char *fmt, ...)
1871da0a9f2SSimon Schubert {
1881da0a9f2SSimon Schubert va_list ap;
189c8b07ee5SSascha Wildner char outs[ERRMSG_SIZE];
1901da0a9f2SSimon Schubert
191c8b07ee5SSascha Wildner outs[0] = 0;
1921da0a9f2SSimon Schubert if (fmt != NULL) {
1931da0a9f2SSimon Schubert va_start(ap, fmt);
194c8b07ee5SSascha Wildner vsnprintf(outs, sizeof(outs), fmt, ap);
1951da0a9f2SSimon Schubert va_end(ap);
1961da0a9f2SSimon Schubert }
1971da0a9f2SSimon Schubert
198c8b07ee5SSascha Wildner if (*outs != 0) {
1991da0a9f2SSimon Schubert syslog(LOG_ERR, "%s", outs);
2001da0a9f2SSimon Schubert fprintf(stderr, "%s: %s\n", getprogname(), outs);
2011da0a9f2SSimon Schubert } else {
2021da0a9f2SSimon Schubert syslog(LOG_ERR, "Unknown error");
2031da0a9f2SSimon Schubert fprintf(stderr, "%s: Unknown error\n", getprogname());
2041da0a9f2SSimon Schubert }
2051da0a9f2SSimon Schubert
2061da0a9f2SSimon Schubert exit(exitcode);
2071da0a9f2SSimon Schubert }
2081da0a9f2SSimon Schubert
209c8b07ee5SSascha Wildner static int
check_username(const char * name,uid_t ckuid)2101da0a9f2SSimon Schubert check_username(const char *name, uid_t ckuid)
2111da0a9f2SSimon Schubert {
2121da0a9f2SSimon Schubert struct passwd *pwd;
2131da0a9f2SSimon Schubert
2141da0a9f2SSimon Schubert if (name == NULL)
215c8b07ee5SSascha Wildner return (0);
2161da0a9f2SSimon Schubert pwd = getpwnam(name);
2171da0a9f2SSimon Schubert if (pwd == NULL || pwd->pw_uid != ckuid)
218c8b07ee5SSascha Wildner return (0);
219c8b07ee5SSascha Wildner snprintf(username, sizeof(username), "%s", name);
220c8b07ee5SSascha Wildner return (1);
2211da0a9f2SSimon Schubert }
2221da0a9f2SSimon Schubert
2231da0a9f2SSimon Schubert void
set_username(void)2241da0a9f2SSimon Schubert set_username(void)
2251da0a9f2SSimon Schubert {
2261da0a9f2SSimon Schubert struct passwd *pwd;
2271da0a9f2SSimon Schubert
228c8b07ee5SSascha Wildner useruid = getuid();
229c8b07ee5SSascha Wildner if (check_username(getlogin(), useruid))
2301da0a9f2SSimon Schubert return;
231c8b07ee5SSascha Wildner if (check_username(getenv("LOGNAME"), useruid))
2321da0a9f2SSimon Schubert return;
233c8b07ee5SSascha Wildner if (check_username(getenv("USER"), useruid))
2341da0a9f2SSimon Schubert return;
235c8b07ee5SSascha Wildner pwd = getpwuid(useruid);
236c8b07ee5SSascha Wildner if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') {
237c8b07ee5SSascha Wildner if (check_username(pwd->pw_name, useruid))
2381da0a9f2SSimon Schubert return;
2391da0a9f2SSimon Schubert }
240c8b07ee5SSascha Wildner snprintf(username, sizeof(username), "uid=%ld", (long)useruid);
2411da0a9f2SSimon Schubert }
2421da0a9f2SSimon Schubert
2431da0a9f2SSimon Schubert void
deltmp(void)2441da0a9f2SSimon Schubert deltmp(void)
2451da0a9f2SSimon Schubert {
2461da0a9f2SSimon Schubert struct stritem *t;
2471da0a9f2SSimon Schubert
2481da0a9f2SSimon Schubert SLIST_FOREACH(t, &tmpfs, next) {
2491da0a9f2SSimon Schubert unlink(t->str);
2501da0a9f2SSimon Schubert }
2511da0a9f2SSimon Schubert }
2521da0a9f2SSimon Schubert
253c8b07ee5SSascha Wildner static sigjmp_buf sigbuf;
254c8b07ee5SSascha Wildner static int sigbuf_valid;
255c8b07ee5SSascha Wildner
256c8b07ee5SSascha Wildner static void
sigalrm_handler(int signo)257c8b07ee5SSascha Wildner sigalrm_handler(int signo)
258c8b07ee5SSascha Wildner {
259c8b07ee5SSascha Wildner (void)signo; /* so that gcc doesn't complain */
260c8b07ee5SSascha Wildner if (sigbuf_valid)
261c8b07ee5SSascha Wildner siglongjmp(sigbuf, 1);
262c8b07ee5SSascha Wildner }
263c8b07ee5SSascha Wildner
264c8b07ee5SSascha Wildner int
do_timeout(int timeout,int dojmp)265c8b07ee5SSascha Wildner do_timeout(int timeout, int dojmp)
266c8b07ee5SSascha Wildner {
267c8b07ee5SSascha Wildner struct sigaction act;
268c8b07ee5SSascha Wildner int ret = 0;
269c8b07ee5SSascha Wildner
270c8b07ee5SSascha Wildner sigemptyset(&act.sa_mask);
271c8b07ee5SSascha Wildner act.sa_flags = 0;
272c8b07ee5SSascha Wildner
273c8b07ee5SSascha Wildner if (timeout) {
274c8b07ee5SSascha Wildner act.sa_handler = sigalrm_handler;
275c8b07ee5SSascha Wildner if (sigaction(SIGALRM, &act, NULL) != 0)
276c8b07ee5SSascha Wildner syslog(LOG_WARNING, "can not set signal handler: %m");
277c8b07ee5SSascha Wildner if (dojmp) {
278c8b07ee5SSascha Wildner ret = sigsetjmp(sigbuf, 1);
279c8b07ee5SSascha Wildner if (ret)
280c8b07ee5SSascha Wildner goto disable;
281c8b07ee5SSascha Wildner /* else just programmed */
282c8b07ee5SSascha Wildner sigbuf_valid = 1;
283c8b07ee5SSascha Wildner }
284c8b07ee5SSascha Wildner
285c8b07ee5SSascha Wildner alarm(timeout);
286c8b07ee5SSascha Wildner } else {
287c8b07ee5SSascha Wildner disable:
288c8b07ee5SSascha Wildner alarm(0);
289c8b07ee5SSascha Wildner
290c8b07ee5SSascha Wildner act.sa_handler = SIG_IGN;
291c8b07ee5SSascha Wildner if (sigaction(SIGALRM, &act, NULL) != 0)
292c8b07ee5SSascha Wildner syslog(LOG_WARNING, "can not remove signal handler: %m");
293c8b07ee5SSascha Wildner sigbuf_valid = 0;
294c8b07ee5SSascha Wildner }
295c8b07ee5SSascha Wildner
296c8b07ee5SSascha Wildner return (ret);
297c8b07ee5SSascha Wildner }
298c8b07ee5SSascha Wildner
2991da0a9f2SSimon Schubert int
open_locked(const char * fname,int flags,...)3001da0a9f2SSimon Schubert open_locked(const char *fname, int flags, ...)
3011da0a9f2SSimon Schubert {
3021da0a9f2SSimon Schubert int mode = 0;
3031da0a9f2SSimon Schubert
3041da0a9f2SSimon Schubert if (flags & O_CREAT) {
3051da0a9f2SSimon Schubert va_list ap;
3061da0a9f2SSimon Schubert va_start(ap, flags);
3071da0a9f2SSimon Schubert mode = va_arg(ap, int);
3081da0a9f2SSimon Schubert va_end(ap);
3091da0a9f2SSimon Schubert }
3101da0a9f2SSimon Schubert
3111da0a9f2SSimon Schubert #ifndef O_EXLOCK
3121da0a9f2SSimon Schubert int fd, save_errno;
3131da0a9f2SSimon Schubert
3141da0a9f2SSimon Schubert fd = open(fname, flags, mode);
3151da0a9f2SSimon Schubert if (fd < 0)
3161da0a9f2SSimon Schubert return(fd);
3171da0a9f2SSimon Schubert if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
3181da0a9f2SSimon Schubert save_errno = errno;
3191da0a9f2SSimon Schubert close(fd);
3201da0a9f2SSimon Schubert errno = save_errno;
3211da0a9f2SSimon Schubert return(-1);
3221da0a9f2SSimon Schubert }
3231da0a9f2SSimon Schubert return(fd);
3241da0a9f2SSimon Schubert #else
3251da0a9f2SSimon Schubert return(open(fname, flags|O_EXLOCK, mode));
3261da0a9f2SSimon Schubert #endif
3271da0a9f2SSimon Schubert }
3281da0a9f2SSimon Schubert
3291da0a9f2SSimon Schubert char *
rfc822date(void)3301da0a9f2SSimon Schubert rfc822date(void)
3311da0a9f2SSimon Schubert {
3321da0a9f2SSimon Schubert static char str[50];
3331da0a9f2SSimon Schubert size_t error;
3341da0a9f2SSimon Schubert time_t now;
3351da0a9f2SSimon Schubert
3361da0a9f2SSimon Schubert now = time(NULL);
3371da0a9f2SSimon Schubert error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
3381da0a9f2SSimon Schubert localtime(&now));
3391da0a9f2SSimon Schubert if (error == 0)
3401da0a9f2SSimon Schubert strcpy(str, "(date fail)");
3411da0a9f2SSimon Schubert return (str);
3421da0a9f2SSimon Schubert }
3431da0a9f2SSimon Schubert
3441da0a9f2SSimon Schubert int
strprefixcmp(const char * str,const char * prefix)3451da0a9f2SSimon Schubert strprefixcmp(const char *str, const char *prefix)
3461da0a9f2SSimon Schubert {
3471da0a9f2SSimon Schubert return (strncasecmp(str, prefix, strlen(prefix)));
3481da0a9f2SSimon Schubert }
3491da0a9f2SSimon Schubert
350c8b07ee5SSascha Wildner void
init_random(void)351c8b07ee5SSascha Wildner init_random(void)
352c8b07ee5SSascha Wildner {
353c8b07ee5SSascha Wildner unsigned int seed;
354c8b07ee5SSascha Wildner int rf;
355c8b07ee5SSascha Wildner
356c8b07ee5SSascha Wildner rf = open("/dev/urandom", O_RDONLY);
357c8b07ee5SSascha Wildner if (rf == -1)
358c8b07ee5SSascha Wildner rf = open("/dev/random", O_RDONLY);
359c8b07ee5SSascha Wildner
360c8b07ee5SSascha Wildner if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed)))
361c8b07ee5SSascha Wildner seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed;
362c8b07ee5SSascha Wildner
363c8b07ee5SSascha Wildner srandom(seed);
364c8b07ee5SSascha Wildner
365c8b07ee5SSascha Wildner if (rf != -1)
366c8b07ee5SSascha Wildner close(rf);
367c8b07ee5SSascha Wildner }
368