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