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 *
hostname(void)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 snprintf(name, sizeof(name), "%s", systemhostname());
103
104 initialized = 1;
105 return (name);
106 }
107
108 const char *
systemhostname(void)109 systemhostname(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
140 void
setlogident(const char * fmt,...)141 setlogident(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
159 void
errlog(int exitcode,const char * fmt,...)160 errlog(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
185 void
errlogx(int exitcode,const char * fmt,...)186 errlogx(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
209 static int
check_username(const char * name,uid_t ckuid)210 check_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
223 void
set_username(void)224 set_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
243 void
deltmp(void)244 deltmp(void)
245 {
246 struct stritem *t;
247
248 SLIST_FOREACH(t, &tmpfs, next) {
249 unlink(t->str);
250 }
251 }
252
253 static sigjmp_buf sigbuf;
254 static int sigbuf_valid;
255
256 static void
sigalrm_handler(int signo)257 sigalrm_handler(int signo)
258 {
259 (void)signo; /* so that gcc doesn't complain */
260 if (sigbuf_valid)
261 siglongjmp(sigbuf, 1);
262 }
263
264 int
do_timeout(int timeout,int dojmp)265 do_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 {
287 disable:
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
299 int
open_locked(const char * fname,int flags,...)300 open_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
329 char *
rfc822date(void)330 rfc822date(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
344 int
strprefixcmp(const char * str,const char * prefix)345 strprefixcmp(const char *str, const char *prefix)
346 {
347 return (strncasecmp(str, prefix, strlen(prefix)));
348 }
349
350 void
init_random(void)351 init_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