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