1262266Sbapt/* 2289123Sbapt * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. 3262266Sbapt * Copyright (c) 2008 The DragonFly Project. All rights reserved. 4262266Sbapt * 5262266Sbapt * This code is derived from software contributed to The DragonFly Project 6289123Sbapt * by Simon Schubert <2@0x2c.org>. 7262266Sbapt * 8262266Sbapt * Redistribution and use in source and binary forms, with or without 9262266Sbapt * modification, are permitted provided that the following conditions 10262266Sbapt * are met: 11262266Sbapt * 12262266Sbapt * 1. Redistributions of source code must retain the above copyright 13262266Sbapt * notice, this list of conditions and the following disclaimer. 14262266Sbapt * 2. Redistributions in binary form must reproduce the above copyright 15262266Sbapt * notice, this list of conditions and the following disclaimer in 16262266Sbapt * the documentation and/or other materials provided with the 17262266Sbapt * distribution. 18262266Sbapt * 3. Neither the name of The DragonFly Project nor the names of its 19262266Sbapt * contributors may be used to endorse or promote products derived 20262266Sbapt * from this software without specific, prior written permission. 21262266Sbapt * 22262266Sbapt * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23262266Sbapt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24262266Sbapt * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25262266Sbapt * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26262266Sbapt * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27262266Sbapt * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28262266Sbapt * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29262266Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30262266Sbapt * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31262266Sbapt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32262266Sbapt * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33262266Sbapt * SUCH DAMAGE. 34262266Sbapt */ 35262266Sbapt 36262266Sbapt#include <sys/param.h> 37262266Sbapt#include <sys/file.h> 38262266Sbapt 39262266Sbapt#include <ctype.h> 40262266Sbapt#include <errno.h> 41262266Sbapt#include <fcntl.h> 42262266Sbapt#include <netdb.h> 43262266Sbapt#include <pwd.h> 44262266Sbapt#include <setjmp.h> 45262266Sbapt#include <signal.h> 46262266Sbapt#include <stdio.h> 47262266Sbapt#include <syslog.h> 48262266Sbapt#include <unistd.h> 49262266Sbapt 50262266Sbapt#include "dma.h" 51262266Sbapt 52262266Sbaptconst char * 53262266Sbapthostname(void) 54262266Sbapt{ 55262266Sbapt#ifndef HOST_NAME_MAX 56262266Sbapt#define HOST_NAME_MAX 255 57262266Sbapt#endif 58262266Sbapt static char name[HOST_NAME_MAX+1]; 59262266Sbapt static int initialized = 0; 60262266Sbapt char *s; 61262266Sbapt 62262266Sbapt if (initialized) 63262266Sbapt return (name); 64262266Sbapt 65262266Sbapt if (config.mailname == NULL || !*config.mailname) 66262266Sbapt goto local; 67262266Sbapt 68262266Sbapt if (config.mailname[0] == '/') { 69262266Sbapt /* 70262266Sbapt * If the mailname looks like an absolute path, 71262266Sbapt * treat it as a file. 72262266Sbapt */ 73262266Sbapt FILE *fp; 74262266Sbapt 75262266Sbapt fp = fopen(config.mailname, "r"); 76262266Sbapt if (fp == NULL) 77262266Sbapt goto local; 78262266Sbapt 79262266Sbapt s = fgets(name, sizeof(name), fp); 80262266Sbapt fclose(fp); 81262266Sbapt if (s == NULL) 82262266Sbapt goto local; 83262266Sbapt 84262266Sbapt for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) 85262266Sbapt /* NOTHING */; 86262266Sbapt *s = 0; 87262266Sbapt 88262266Sbapt if (!*name) 89262266Sbapt goto local; 90262266Sbapt 91262266Sbapt initialized = 1; 92262266Sbapt return (name); 93262266Sbapt } else { 94262266Sbapt snprintf(name, sizeof(name), "%s", config.mailname); 95262266Sbapt initialized = 1; 96262266Sbapt return (name); 97262266Sbapt } 98262266Sbapt 99262266Sbaptlocal: 100262266Sbapt if (gethostname(name, sizeof(name)) != 0) 101262266Sbapt *name = 0; 102262266Sbapt /* 103262266Sbapt * gethostname() is allowed to truncate name without NUL-termination 104262266Sbapt * and at the same time not return an error. 105262266Sbapt */ 106262266Sbapt name[sizeof(name) - 1] = 0; 107262266Sbapt 108262266Sbapt for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) 109262266Sbapt /* NOTHING */; 110262266Sbapt *s = 0; 111262266Sbapt 112262266Sbapt if (!*name) 113262266Sbapt snprintf(name, sizeof(name), "unknown-hostname"); 114262266Sbapt 115262266Sbapt initialized = 1; 116262266Sbapt return (name); 117262266Sbapt} 118262266Sbapt 119262266Sbaptvoid 120262266Sbaptsetlogident(const char *fmt, ...) 121262266Sbapt{ 122262266Sbapt static char tag[50]; 123262266Sbapt 124262266Sbapt snprintf(tag, sizeof(tag), "%s", logident_base); 125262266Sbapt if (fmt != NULL) { 126262266Sbapt va_list ap; 127262266Sbapt char sufx[50]; 128262266Sbapt 129262266Sbapt va_start(ap, fmt); 130262266Sbapt vsnprintf(sufx, sizeof(sufx), fmt, ap); 131262266Sbapt va_end(ap); 132262266Sbapt snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx); 133262266Sbapt } 134262266Sbapt closelog(); 135262266Sbapt openlog(tag, 0, LOG_MAIL); 136262266Sbapt} 137262266Sbapt 138262266Sbaptvoid 139262266Sbapterrlog(int exitcode, const char *fmt, ...) 140262266Sbapt{ 141262266Sbapt int oerrno = errno; 142262266Sbapt va_list ap; 143262266Sbapt char outs[ERRMSG_SIZE]; 144262266Sbapt 145262266Sbapt outs[0] = 0; 146262266Sbapt if (fmt != NULL) { 147262266Sbapt va_start(ap, fmt); 148262266Sbapt vsnprintf(outs, sizeof(outs), fmt, ap); 149262266Sbapt va_end(ap); 150262266Sbapt } 151262266Sbapt 152262266Sbapt errno = oerrno; 153262266Sbapt if (*outs != 0) { 154262266Sbapt syslog(LOG_ERR, "%s: %m", outs); 155262266Sbapt fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno)); 156262266Sbapt } else { 157262266Sbapt syslog(LOG_ERR, "%m"); 158262266Sbapt fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno)); 159262266Sbapt } 160262266Sbapt 161262266Sbapt exit(exitcode); 162262266Sbapt} 163262266Sbapt 164262266Sbaptvoid 165262266Sbapterrlogx(int exitcode, const char *fmt, ...) 166262266Sbapt{ 167262266Sbapt va_list ap; 168262266Sbapt char outs[ERRMSG_SIZE]; 169262266Sbapt 170262266Sbapt outs[0] = 0; 171262266Sbapt if (fmt != NULL) { 172262266Sbapt va_start(ap, fmt); 173262266Sbapt vsnprintf(outs, sizeof(outs), fmt, ap); 174262266Sbapt va_end(ap); 175262266Sbapt } 176262266Sbapt 177262266Sbapt if (*outs != 0) { 178262266Sbapt syslog(LOG_ERR, "%s", outs); 179262266Sbapt fprintf(stderr, "%s: %s\n", getprogname(), outs); 180262266Sbapt } else { 181262266Sbapt syslog(LOG_ERR, "Unknown error"); 182262266Sbapt fprintf(stderr, "%s: Unknown error\n", getprogname()); 183262266Sbapt } 184262266Sbapt 185262266Sbapt exit(exitcode); 186262266Sbapt} 187262266Sbapt 188262266Sbaptstatic int 189262266Sbaptcheck_username(const char *name, uid_t ckuid) 190262266Sbapt{ 191262266Sbapt struct passwd *pwd; 192262266Sbapt 193262266Sbapt if (name == NULL) 194262266Sbapt return (0); 195262266Sbapt pwd = getpwnam(name); 196262266Sbapt if (pwd == NULL || pwd->pw_uid != ckuid) 197262266Sbapt return (0); 198262266Sbapt snprintf(username, sizeof(username), "%s", name); 199262266Sbapt return (1); 200262266Sbapt} 201262266Sbapt 202262266Sbaptvoid 203262266Sbaptset_username(void) 204262266Sbapt{ 205262266Sbapt struct passwd *pwd; 206262266Sbapt 207262266Sbapt useruid = getuid(); 208262266Sbapt if (check_username(getlogin(), useruid)) 209262266Sbapt return; 210262266Sbapt if (check_username(getenv("LOGNAME"), useruid)) 211262266Sbapt return; 212262266Sbapt if (check_username(getenv("USER"), useruid)) 213262266Sbapt return; 214262266Sbapt pwd = getpwuid(useruid); 215262266Sbapt if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') { 216262266Sbapt if (check_username(pwd->pw_name, useruid)) 217262266Sbapt return; 218262266Sbapt } 219262266Sbapt snprintf(username, sizeof(username), "uid=%ld", (long)useruid); 220262266Sbapt} 221262266Sbapt 222262266Sbaptvoid 223262266Sbaptdeltmp(void) 224262266Sbapt{ 225262266Sbapt struct stritem *t; 226262266Sbapt 227262266Sbapt SLIST_FOREACH(t, &tmpfs, next) { 228262266Sbapt unlink(t->str); 229262266Sbapt } 230262266Sbapt} 231262266Sbapt 232262266Sbaptstatic sigjmp_buf sigbuf; 233262266Sbaptstatic int sigbuf_valid; 234262266Sbapt 235262266Sbaptstatic void 236262266Sbaptsigalrm_handler(int signo) 237262266Sbapt{ 238262266Sbapt (void)signo; /* so that gcc doesn't complain */ 239262266Sbapt if (sigbuf_valid) 240262266Sbapt siglongjmp(sigbuf, 1); 241262266Sbapt} 242262266Sbapt 243262266Sbaptint 244262266Sbaptdo_timeout(int timeout, int dojmp) 245262266Sbapt{ 246262266Sbapt struct sigaction act; 247262266Sbapt int ret = 0; 248262266Sbapt 249262266Sbapt sigemptyset(&act.sa_mask); 250262266Sbapt act.sa_flags = 0; 251262266Sbapt 252262266Sbapt if (timeout) { 253262266Sbapt act.sa_handler = sigalrm_handler; 254262266Sbapt if (sigaction(SIGALRM, &act, NULL) != 0) 255262266Sbapt syslog(LOG_WARNING, "can not set signal handler: %m"); 256262266Sbapt if (dojmp) { 257262266Sbapt ret = sigsetjmp(sigbuf, 1); 258262266Sbapt if (ret) 259262266Sbapt goto disable; 260262266Sbapt /* else just programmed */ 261262266Sbapt sigbuf_valid = 1; 262262266Sbapt } 263262266Sbapt 264262266Sbapt alarm(timeout); 265262266Sbapt } else { 266262266Sbaptdisable: 267262266Sbapt alarm(0); 268262266Sbapt 269262266Sbapt act.sa_handler = SIG_IGN; 270262266Sbapt if (sigaction(SIGALRM, &act, NULL) != 0) 271262266Sbapt syslog(LOG_WARNING, "can not remove signal handler: %m"); 272262266Sbapt sigbuf_valid = 0; 273262266Sbapt } 274262266Sbapt 275262266Sbapt return (ret); 276262266Sbapt} 277262266Sbapt 278262266Sbaptint 279262266Sbaptopen_locked(const char *fname, int flags, ...) 280262266Sbapt{ 281262266Sbapt int mode = 0; 282262266Sbapt 283262266Sbapt if (flags & O_CREAT) { 284262266Sbapt va_list ap; 285262266Sbapt va_start(ap, flags); 286262266Sbapt mode = va_arg(ap, int); 287262266Sbapt va_end(ap); 288262266Sbapt } 289262266Sbapt 290262266Sbapt#ifndef O_EXLOCK 291262266Sbapt int fd, save_errno; 292262266Sbapt 293262266Sbapt fd = open(fname, flags, mode); 294262266Sbapt if (fd < 0) 295262266Sbapt return(fd); 296262266Sbapt if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) { 297262266Sbapt save_errno = errno; 298262266Sbapt close(fd); 299262266Sbapt errno = save_errno; 300262266Sbapt return(-1); 301262266Sbapt } 302262266Sbapt return(fd); 303262266Sbapt#else 304262266Sbapt return(open(fname, flags|O_EXLOCK, mode)); 305262266Sbapt#endif 306262266Sbapt} 307262266Sbapt 308262266Sbaptchar * 309262266Sbaptrfc822date(void) 310262266Sbapt{ 311262266Sbapt static char str[50]; 312262266Sbapt size_t error; 313262266Sbapt time_t now; 314262266Sbapt 315262266Sbapt now = time(NULL); 316262266Sbapt error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z", 317262266Sbapt localtime(&now)); 318262266Sbapt if (error == 0) 319262266Sbapt strcpy(str, "(date fail)"); 320262266Sbapt return (str); 321262266Sbapt} 322262266Sbapt 323262266Sbaptint 324262266Sbaptstrprefixcmp(const char *str, const char *prefix) 325262266Sbapt{ 326262266Sbapt return (strncasecmp(str, prefix, strlen(prefix))); 327262266Sbapt} 328262266Sbapt 329262266Sbaptvoid 330262266Sbaptinit_random(void) 331262266Sbapt{ 332262266Sbapt unsigned int seed; 333262266Sbapt int rf; 334262266Sbapt 335262266Sbapt rf = open("/dev/urandom", O_RDONLY); 336262266Sbapt if (rf == -1) 337262266Sbapt rf = open("/dev/random", O_RDONLY); 338262266Sbapt 339262266Sbapt if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed))) 340262266Sbapt seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed; 341262266Sbapt 342262266Sbapt srandom(seed); 343262266Sbapt 344262266Sbapt if (rf != -1) 345262266Sbapt close(rf); 346262266Sbapt} 347