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