1 /*
2 * Copyright (c) 2008-2014, Simon Schubert <[email protected]>.
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 <[email protected]>.
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 *
hostname(void)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
setlogident(const char * fmt,...)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
errlog(int exitcode,const char * fmt,...)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
errlogx(int exitcode,const char * fmt,...)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
check_username(const char * name,uid_t ckuid)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
set_username(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
deltmp(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
sigalrm_handler(int signo)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
do_timeout(int timeout,int dojmp)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
open_locked(const char * fname,int flags,...)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 *
rfc822date(void)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
strprefixcmp(const char * str,const char * prefix)325 strprefixcmp(const char *str, const char *prefix)
326 {
327 return (strncasecmp(str, prefix, strlen(prefix)));
328 }
329
330 void
init_random(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