xref: /freebsd/contrib/dma/util.c (revision 85732ac8)
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 
53 const char *
54 hostname(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 
100 local:
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 
120 void
121 setlogident(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 
139 void
140 errlog(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 
165 void
166 errlogx(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 
189 static int
190 check_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 
203 void
204 set_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 
223 void
224 deltmp(void)
225 {
226 	struct stritem *t;
227 
228 	SLIST_FOREACH(t, &tmpfs, next) {
229 		unlink(t->str);
230 	}
231 }
232 
233 static sigjmp_buf sigbuf;
234 static int sigbuf_valid;
235 
236 static void
237 sigalrm_handler(int signo)
238 {
239 	(void)signo;	/* so that gcc doesn't complain */
240 	if (sigbuf_valid)
241 		siglongjmp(sigbuf, 1);
242 }
243 
244 int
245 do_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 {
267 disable:
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 
279 int
280 open_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 
309 char *
310 rfc822date(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 
324 int
325 strprefixcmp(const char *str, const char *prefix)
326 {
327 	return (strncasecmp(str, prefix, strlen(prefix)));
328 }
329 
330 void
331 init_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