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 <string.h> 48 #include <syslog.h> 49 #include <unistd.h> 50 51 #include "dma.h" 52 53 const char * 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 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 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 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 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 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 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 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 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 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 * 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 325 strprefixcmp(const char *str, const char *prefix) 326 { 327 return (strncasecmp(str, prefix, strlen(prefix))); 328 } 329 330 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