xref: /dragonfly/libexec/dma/util.c (revision 577b958f5e57e9712ddc260c6666d661d03397fe)
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