1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/file.h> 37 38 #include <ctype.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <netdb.h> 42 #include <pwd.h> 43 #include <setjmp.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <syslog.h> 47 #include <unistd.h> 48 49 #include "dma.h" 50 51 const char * 52 hostname(void) 53 { 54 #ifndef HOST_NAME_MAX 55 #define HOST_NAME_MAX 255 56 #endif 57 static char name[HOST_NAME_MAX+1]; 58 static int initialized = 0; 59 char *s; 60 61 if (initialized) 62 return (name); 63 64 if (config.mailname == NULL || !*config.mailname) 65 goto local; 66 67 if (config.mailname[0] == '/') { 68 /* 69 * If the mailname looks like an absolute path, 70 * treat it as a file. 71 */ 72 FILE *fp; 73 74 fp = fopen(config.mailname, "r"); 75 if (fp == NULL) 76 goto local; 77 78 s = fgets(name, sizeof(name), fp); 79 fclose(fp); 80 if (s == NULL) 81 goto local; 82 83 for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) 84 /* NOTHING */; 85 *s = 0; 86 87 if (!*name) 88 goto local; 89 90 initialized = 1; 91 return (name); 92 } else { 93 snprintf(name, sizeof(name), "%s", config.mailname); 94 initialized = 1; 95 return (name); 96 } 97 98 local: 99 if (gethostname(name, sizeof(name)) != 0) 100 *name = 0; 101 /* 102 * gethostname() is allowed to truncate name without NUL-termination 103 * and at the same time not return an error. 104 */ 105 name[sizeof(name) - 1] = 0; 106 107 for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) 108 /* NOTHING */; 109 *s = 0; 110 111 if (!*name) 112 snprintf(name, sizeof(name), "unknown-hostname"); 113 114 initialized = 1; 115 return (name); 116 } 117 118 void 119 setlogident(const char *fmt, ...) 120 { 121 static char tag[50]; 122 123 snprintf(tag, sizeof(tag), "%s", logident_base); 124 if (fmt != NULL) { 125 va_list ap; 126 char sufx[50]; 127 128 va_start(ap, fmt); 129 vsnprintf(sufx, sizeof(sufx), fmt, ap); 130 va_end(ap); 131 snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx); 132 } 133 closelog(); 134 openlog(tag, 0, LOG_MAIL); 135 } 136 137 void 138 errlog(int exitcode, const char *fmt, ...) 139 { 140 int oerrno = errno; 141 va_list ap; 142 char outs[ERRMSG_SIZE]; 143 144 outs[0] = 0; 145 if (fmt != NULL) { 146 va_start(ap, fmt); 147 vsnprintf(outs, sizeof(outs), fmt, ap); 148 va_end(ap); 149 } 150 151 errno = oerrno; 152 if (*outs != 0) { 153 syslog(LOG_ERR, "%s: %m", outs); 154 fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno)); 155 } else { 156 syslog(LOG_ERR, "%m"); 157 fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno)); 158 } 159 160 exit(exitcode); 161 } 162 163 void 164 errlogx(int exitcode, const char *fmt, ...) 165 { 166 va_list ap; 167 char outs[ERRMSG_SIZE]; 168 169 outs[0] = 0; 170 if (fmt != NULL) { 171 va_start(ap, fmt); 172 vsnprintf(outs, sizeof(outs), fmt, ap); 173 va_end(ap); 174 } 175 176 if (*outs != 0) { 177 syslog(LOG_ERR, "%s", outs); 178 fprintf(stderr, "%s: %s\n", getprogname(), outs); 179 } else { 180 syslog(LOG_ERR, "Unknown error"); 181 fprintf(stderr, "%s: Unknown error\n", getprogname()); 182 } 183 184 exit(exitcode); 185 } 186 187 static int 188 check_username(const char *name, uid_t ckuid) 189 { 190 struct passwd *pwd; 191 192 if (name == NULL) 193 return (0); 194 pwd = getpwnam(name); 195 if (pwd == NULL || pwd->pw_uid != ckuid) 196 return (0); 197 snprintf(username, sizeof(username), "%s", name); 198 return (1); 199 } 200 201 void 202 set_username(void) 203 { 204 struct passwd *pwd; 205 206 useruid = getuid(); 207 if (check_username(getlogin(), useruid)) 208 return; 209 if (check_username(getenv("LOGNAME"), useruid)) 210 return; 211 if (check_username(getenv("USER"), useruid)) 212 return; 213 pwd = getpwuid(useruid); 214 if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') { 215 if (check_username(pwd->pw_name, useruid)) 216 return; 217 } 218 snprintf(username, sizeof(username), "uid=%ld", (long)useruid); 219 } 220 221 void 222 deltmp(void) 223 { 224 struct stritem *t; 225 226 SLIST_FOREACH(t, &tmpfs, next) { 227 unlink(t->str); 228 } 229 } 230 231 static sigjmp_buf sigbuf; 232 static int sigbuf_valid; 233 234 static void 235 sigalrm_handler(int signo) 236 { 237 (void)signo; /* so that gcc doesn't complain */ 238 if (sigbuf_valid) 239 siglongjmp(sigbuf, 1); 240 } 241 242 int 243 do_timeout(int timeout, int dojmp) 244 { 245 struct sigaction act; 246 int ret = 0; 247 248 sigemptyset(&act.sa_mask); 249 act.sa_flags = 0; 250 251 if (timeout) { 252 act.sa_handler = sigalrm_handler; 253 if (sigaction(SIGALRM, &act, NULL) != 0) 254 syslog(LOG_WARNING, "can not set signal handler: %m"); 255 if (dojmp) { 256 ret = sigsetjmp(sigbuf, 1); 257 if (ret) 258 goto disable; 259 /* else just programmed */ 260 sigbuf_valid = 1; 261 } 262 263 alarm(timeout); 264 } else { 265 disable: 266 alarm(0); 267 268 act.sa_handler = SIG_IGN; 269 if (sigaction(SIGALRM, &act, NULL) != 0) 270 syslog(LOG_WARNING, "can not remove signal handler: %m"); 271 sigbuf_valid = 0; 272 } 273 274 return (ret); 275 } 276 277 int 278 open_locked(const char *fname, int flags, ...) 279 { 280 int mode = 0; 281 282 if (flags & O_CREAT) { 283 va_list ap; 284 va_start(ap, flags); 285 mode = va_arg(ap, int); 286 va_end(ap); 287 } 288 289 #ifndef O_EXLOCK 290 int fd, save_errno; 291 292 fd = open(fname, flags, mode); 293 if (fd < 0) 294 return(fd); 295 if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) { 296 save_errno = errno; 297 close(fd); 298 errno = save_errno; 299 return(-1); 300 } 301 return(fd); 302 #else 303 return(open(fname, flags|O_EXLOCK, mode)); 304 #endif 305 } 306 307 char * 308 rfc822date(void) 309 { 310 static char str[50]; 311 size_t error; 312 time_t now; 313 314 now = time(NULL); 315 error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z", 316 localtime(&now)); 317 if (error == 0) 318 strcpy(str, "(date fail)"); 319 return (str); 320 } 321 322 int 323 strprefixcmp(const char *str, const char *prefix) 324 { 325 return (strncasecmp(str, prefix, strlen(prefix))); 326 } 327 328 void 329 init_random(void) 330 { 331 unsigned int seed; 332 int rf; 333 334 rf = open("/dev/urandom", O_RDONLY); 335 if (rf == -1) 336 rf = open("/dev/random", O_RDONLY); 337 338 if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed))) 339 seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed; 340 341 srandom(seed); 342 343 if (rf != -1) 344 close(rf); 345 } 346