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 * 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 if (gethostname(name, sizeof(name)) != 0) 103 *name = 0; 104 /* 105 * gethostname() is allowed to truncate name without NUL-termination 106 * and at the same time not return an error. 107 */ 108 name[sizeof(name) - 1] = 0; 109 110 for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) 111 /* NOTHING */; 112 *s = 0; 113 114 if (!*name) 115 snprintf(name, sizeof(name), "unknown-hostname"); 116 117 initialized = 1; 118 return (name); 119 } 120 121 void 122 setlogident(const char *fmt, ...) 123 { 124 static char tag[50]; 125 126 snprintf(tag, sizeof(tag), "%s", logident_base); 127 if (fmt != NULL) { 128 va_list ap; 129 char sufx[50]; 130 131 va_start(ap, fmt); 132 vsnprintf(sufx, sizeof(sufx), fmt, ap); 133 va_end(ap); 134 snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx); 135 } 136 closelog(); 137 openlog(tag, 0, LOG_MAIL); 138 } 139 140 void 141 errlog(int exitcode, const char *fmt, ...) 142 { 143 int oerrno = errno; 144 va_list ap; 145 char outs[ERRMSG_SIZE]; 146 147 outs[0] = 0; 148 if (fmt != NULL) { 149 va_start(ap, fmt); 150 vsnprintf(outs, sizeof(outs), fmt, ap); 151 va_end(ap); 152 } 153 154 errno = oerrno; 155 if (*outs != 0) { 156 syslog(LOG_ERR, "%s: %m", outs); 157 fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno)); 158 } else { 159 syslog(LOG_ERR, "%m"); 160 fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno)); 161 } 162 163 exit(exitcode); 164 } 165 166 void 167 errlogx(int exitcode, const char *fmt, ...) 168 { 169 va_list ap; 170 char outs[ERRMSG_SIZE]; 171 172 outs[0] = 0; 173 if (fmt != NULL) { 174 va_start(ap, fmt); 175 vsnprintf(outs, sizeof(outs), fmt, ap); 176 va_end(ap); 177 } 178 179 if (*outs != 0) { 180 syslog(LOG_ERR, "%s", outs); 181 fprintf(stderr, "%s: %s\n", getprogname(), outs); 182 } else { 183 syslog(LOG_ERR, "Unknown error"); 184 fprintf(stderr, "%s: Unknown error\n", getprogname()); 185 } 186 187 exit(exitcode); 188 } 189 190 static int 191 check_username(const char *name, uid_t ckuid) 192 { 193 struct passwd *pwd; 194 195 if (name == NULL) 196 return (0); 197 pwd = getpwnam(name); 198 if (pwd == NULL || pwd->pw_uid != ckuid) 199 return (0); 200 snprintf(username, sizeof(username), "%s", name); 201 return (1); 202 } 203 204 void 205 set_username(void) 206 { 207 struct passwd *pwd; 208 209 useruid = getuid(); 210 if (check_username(getlogin(), useruid)) 211 return; 212 if (check_username(getenv("LOGNAME"), useruid)) 213 return; 214 if (check_username(getenv("USER"), useruid)) 215 return; 216 pwd = getpwuid(useruid); 217 if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') { 218 if (check_username(pwd->pw_name, useruid)) 219 return; 220 } 221 snprintf(username, sizeof(username), "uid=%ld", (long)useruid); 222 } 223 224 void 225 deltmp(void) 226 { 227 struct stritem *t; 228 229 SLIST_FOREACH(t, &tmpfs, next) { 230 unlink(t->str); 231 } 232 } 233 234 static sigjmp_buf sigbuf; 235 static int sigbuf_valid; 236 237 static void 238 sigalrm_handler(int signo) 239 { 240 (void)signo; /* so that gcc doesn't complain */ 241 if (sigbuf_valid) 242 siglongjmp(sigbuf, 1); 243 } 244 245 int 246 do_timeout(int timeout, int dojmp) 247 { 248 struct sigaction act; 249 int ret = 0; 250 251 sigemptyset(&act.sa_mask); 252 act.sa_flags = 0; 253 254 if (timeout) { 255 act.sa_handler = sigalrm_handler; 256 if (sigaction(SIGALRM, &act, NULL) != 0) 257 syslog(LOG_WARNING, "can not set signal handler: %m"); 258 if (dojmp) { 259 ret = sigsetjmp(sigbuf, 1); 260 if (ret) 261 goto disable; 262 /* else just programmed */ 263 sigbuf_valid = 1; 264 } 265 266 alarm(timeout); 267 } else { 268 disable: 269 alarm(0); 270 271 act.sa_handler = SIG_IGN; 272 if (sigaction(SIGALRM, &act, NULL) != 0) 273 syslog(LOG_WARNING, "can not remove signal handler: %m"); 274 sigbuf_valid = 0; 275 } 276 277 return (ret); 278 } 279 280 int 281 open_locked(const char *fname, int flags, ...) 282 { 283 int mode = 0; 284 285 if (flags & O_CREAT) { 286 va_list ap; 287 va_start(ap, flags); 288 mode = va_arg(ap, int); 289 va_end(ap); 290 } 291 292 #ifndef O_EXLOCK 293 int fd, save_errno; 294 295 fd = open(fname, flags, mode); 296 if (fd < 0) 297 return(fd); 298 if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) { 299 save_errno = errno; 300 close(fd); 301 errno = save_errno; 302 return(-1); 303 } 304 return(fd); 305 #else 306 return(open(fname, flags|O_EXLOCK, mode)); 307 #endif 308 } 309 310 char * 311 rfc822date(void) 312 { 313 static char str[50]; 314 size_t error; 315 time_t now; 316 317 now = time(NULL); 318 error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z", 319 localtime(&now)); 320 if (error == 0) 321 strcpy(str, "(date fail)"); 322 return (str); 323 } 324 325 int 326 strprefixcmp(const char *str, const char *prefix) 327 { 328 return (strncasecmp(str, prefix, strlen(prefix))); 329 } 330 331 void 332 init_random(void) 333 { 334 unsigned int seed; 335 int rf; 336 337 rf = open("/dev/urandom", O_RDONLY); 338 if (rf == -1) 339 rf = open("/dev/random", O_RDONLY); 340 341 if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed))) 342 seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed; 343 344 srandom(seed); 345 346 if (rf != -1) 347 close(rf); 348 } 349