2001-08-28 12:33:54 +08:00
|
|
|
/* $Id: utils.c,v 1.7 2001-08-28 04:33:54 rjkaes Exp $
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
|
|
|
* Misc. routines which are used by the various functions to handle strings
|
|
|
|
* and memory allocation and pretty much anything else we can think of. Also,
|
2000-09-12 08:01:29 +08:00
|
|
|
* the load cutoff routine is in here. Could not think of a better place for
|
|
|
|
* it, so it's in here.
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
|
|
|
* Copyright (C) 1998 Steven Young
|
|
|
|
* Copyright (C) 1999 Robert James Kaes (rjkaes@flarenet.com)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
#include "tinyproxy.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <signal.h>
|
2000-09-12 08:01:29 +08:00
|
|
|
#include <sysexits.h>
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
#include "buffer.h"
|
2000-09-12 08:01:29 +08:00
|
|
|
#include "log.h"
|
|
|
|
#include "sock.h"
|
|
|
|
#include "utils.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the start of the needle in the haystack. Limits the search to less
|
|
|
|
* than "length" characters. Returns NULL if the needle is not found.
|
|
|
|
*/
|
2000-09-12 08:01:29 +08:00
|
|
|
char *xstrstr(char *haystack, char *needle, size_t length,
|
|
|
|
bool_t case_sensitive)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
/* Used to specify which function to use... need the decl. */
|
2000-09-12 08:01:29 +08:00
|
|
|
int (*fn) (const char *s1, const char *s2, size_t n);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
if (case_sensitive)
|
|
|
|
fn = strncmp;
|
|
|
|
else
|
|
|
|
fn = strncasecmp;
|
|
|
|
|
|
|
|
if (strlen(needle) > length)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i <= length - strlen(needle); i++) {
|
|
|
|
if ((*fn) (haystack + i, needle, strlen(needle)) == 0)
|
2000-09-12 08:01:29 +08:00
|
|
|
return (haystack + i);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:01:29 +08:00
|
|
|
* Display an error to the client.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-08-27 11:45:34 +08:00
|
|
|
#define HEADER_SIZE (1024 * 8)
|
|
|
|
int httperr(struct conn_s *connptr, int err, const char *msg)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-08-27 11:45:34 +08:00
|
|
|
static char *headers = \
|
|
|
|
"HTTP/1.0 %d %s\r\n" \
|
|
|
|
"Server: %s/%s\r\n" \
|
|
|
|
"Date: %s\r\n" \
|
2001-08-28 01:46:50 +08:00
|
|
|
"Content-Type: text/html\r\n" \
|
2001-08-27 11:45:34 +08:00
|
|
|
"Content-Length: %d\r\n" \
|
|
|
|
"Connection: close\r\n" \
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static char *message = \
|
2000-09-12 08:01:29 +08:00
|
|
|
"<html><head><title>%s</title></head>\r\n" \
|
|
|
|
"<body>\r\n" \
|
|
|
|
"<font size=\"+2\">Cache Error!</font><br>\r\n" \
|
|
|
|
"An error of type %d occurred: %s\r\n" \
|
|
|
|
"<hr>\r\n" \
|
2001-08-28 12:33:54 +08:00
|
|
|
"<font size=\"-1\"><em>Generated by %s (%s)</em></font>\r\n" \
|
|
|
|
"</body></html>\r\n\r\n";
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-08-27 11:45:34 +08:00
|
|
|
char *header_buffer;
|
|
|
|
char *message_buffer;
|
|
|
|
int output_size;
|
|
|
|
char timebuf[30];
|
|
|
|
time_t global_time;
|
|
|
|
|
|
|
|
header_buffer = malloc(HEADER_SIZE);
|
|
|
|
if (!header_buffer) {
|
|
|
|
log_message(LOG_CRIT, "Out of memory!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
message_buffer = malloc(MAXBUFFSIZE);
|
|
|
|
if (!message_buffer) {
|
|
|
|
log_message(LOG_CRIT, "Out of memory!");
|
|
|
|
safefree(header_buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
global_time = time(NULL);
|
|
|
|
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&global_time));
|
|
|
|
|
|
|
|
snprintf(message_buffer, MAXBUFFSIZE - 1, message, msg, err, msg, PACKAGE, VERSION);
|
|
|
|
snprintf(header_buffer, HEADER_SIZE - 1, headers, err, msg, PACKAGE, VERSION, timebuf, strlen(message_buffer));
|
|
|
|
|
|
|
|
output_size = strlen(message_buffer) + strlen(header_buffer);
|
|
|
|
connptr->output_message = malloc(output_size + 1);
|
2000-09-12 08:01:29 +08:00
|
|
|
if (!connptr->output_message) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_CRIT, "Out of memory!");
|
2001-08-27 11:45:34 +08:00
|
|
|
safefree(header_buffer);
|
|
|
|
safefree(message_buffer);
|
2000-02-17 01:32:49 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-08-27 11:45:34 +08:00
|
|
|
strlcpy(connptr->output_message, header_buffer, output_size);
|
|
|
|
strlcat(connptr->output_message, message_buffer, output_size);
|
|
|
|
|
|
|
|
safefree(header_buffer);
|
|
|
|
safefree(message_buffer);
|
2000-09-12 08:01:29 +08:00
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
void makedaemon(void)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:01:29 +08:00
|
|
|
if (fork() != 0)
|
|
|
|
exit(0);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
setsid();
|
|
|
|
signal(SIGHUP, SIG_IGN);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
if (fork() != 0)
|
|
|
|
exit(0);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
chdir("/");
|
|
|
|
umask(077);
|
|
|
|
|
|
|
|
close(0);
|
|
|
|
close(1);
|
|
|
|
close(2);
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
/*
|
2000-09-12 08:01:29 +08:00
|
|
|
* Safely creates filename and returns the low-level file descriptor.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:01:29 +08:00
|
|
|
static int create_file_safely(const char *filename)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:01:29 +08:00
|
|
|
struct stat lstatinfo;
|
|
|
|
int fildes;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lstat() the file. If it doesn't exist, create it with O_EXCL.
|
|
|
|
* If it does exist, open it for writing and perform the fstat()
|
|
|
|
* check.
|
|
|
|
*/
|
|
|
|
if (lstat(filename, &lstatinfo) < 0) {
|
|
|
|
/*
|
|
|
|
* If lstat() failed for any reason other than "file not
|
|
|
|
* existing", exit.
|
|
|
|
*/
|
|
|
|
if (errno != ENOENT) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "Error checking PID file %s: %s",
|
|
|
|
filename, strerror(errno));
|
2000-09-12 08:01:29 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The file doesn't exist, so create it with O_EXCL to make
|
|
|
|
* sure an attacker can't slip in a file between the lstat()
|
|
|
|
* and open()
|
|
|
|
*/
|
|
|
|
if ((fildes = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "Could not create PID file %s: %s",
|
|
|
|
filename, strerror(errno));
|
2000-09-12 08:01:29 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
struct stat fstatinfo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open an existing file.
|
|
|
|
*/
|
|
|
|
if ((fildes = open(filename, O_RDWR)) < 0) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "Could not open PID file %s: %s",
|
|
|
|
filename, strerror(errno));
|
2000-09-12 08:01:29 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fstat() the opened file and check that the file mode bits,
|
|
|
|
* inode, and device match.
|
|
|
|
*/
|
|
|
|
if (fstat(fildes, &fstatinfo) < 0
|
|
|
|
|| lstatinfo.st_mode != fstatinfo.st_mode
|
|
|
|
|| lstatinfo.st_ino != fstatinfo.st_ino
|
|
|
|
|| lstatinfo.st_dev != fstatinfo.st_dev) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "The PID file %s has been changed before it could be opened!",
|
|
|
|
filename);
|
2000-09-12 08:01:29 +08:00
|
|
|
close(fildes);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the above check was passed, we know that the lstat()
|
|
|
|
* and fstat() were done on the same file. Now we check that
|
|
|
|
* there's only one link, and that it's a normal file (this
|
|
|
|
* isn't strictly necessary because the fstat() vs lstat()
|
|
|
|
* st_mode check would also find this)
|
|
|
|
*/
|
|
|
|
if (fstatinfo.st_nlink > 1 || !S_ISREG(lstatinfo.st_mode)) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "The PID file %s has too many links, or is not a regular file: %s",
|
|
|
|
filename, strerror(errno));
|
2000-09-12 08:01:29 +08:00
|
|
|
close(fildes);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On systems whcih don't support ftruncate() the best we can
|
|
|
|
* do is to close the file and reopen it in create mode, which
|
|
|
|
* unfortunately leads to a race condition, however "systems
|
|
|
|
* which don't support ftruncate()" is pretty much SCO only,
|
2001-05-27 10:38:46 +08:00
|
|
|
* and if you're using that you deserve what you get.
|
2000-09-12 08:01:29 +08:00
|
|
|
* ("Little sympathy has been extended")
|
|
|
|
*/
|
2001-05-27 10:38:46 +08:00
|
|
|
#ifdef HAVE_FTRUNCATE
|
|
|
|
ftruncate(fildes, 0);
|
|
|
|
#else
|
2000-09-12 08:01:29 +08:00
|
|
|
close(fildes);
|
|
|
|
if ((fildes = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "Could not open PID file %s: %s",
|
|
|
|
filename, strerror(errno));
|
2000-09-12 08:01:29 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2001-05-27 10:38:46 +08:00
|
|
|
#endif /* HAVE_FTRUNCATE */
|
2000-09-12 08:01:29 +08:00
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
return fildes;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:01:29 +08:00
|
|
|
* Write the PID of the program to the specified file.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:01:29 +08:00
|
|
|
void pidfile_create(const char *filename)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:01:29 +08:00
|
|
|
int fildes;
|
|
|
|
FILE *fd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new file
|
|
|
|
*/
|
|
|
|
if ((fildes = create_file_safely(filename)) < 0)
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a stdio file over the low-level one.
|
|
|
|
*/
|
|
|
|
if ((fd = fdopen(fildes, "w")) == NULL) {
|
2001-05-27 10:38:46 +08:00
|
|
|
log_message(LOG_ERR, "fdopen() error on PID file %s: %s",
|
|
|
|
filename, strerror(errno));
|
2000-09-12 08:01:29 +08:00
|
|
|
close(fildes);
|
|
|
|
unlink(filename);
|
|
|
|
exit(1);
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
fprintf(fd, "%ld\n", (long)getpid());
|
|
|
|
fclose(fd);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
#ifndef HAVE_STRLCPY
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2000-09-12 08:01:29 +08:00
|
|
|
* Function API taken from OpenBSD. Like strncpy(), but does not 0 fill the
|
|
|
|
* buffer, and always NULL terminates the buffer. size is the size of the
|
|
|
|
* destination buffer.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2000-09-12 08:01:29 +08:00
|
|
|
size_t strlcpy(char *dst, const char *src, size_t size)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:01:29 +08:00
|
|
|
size_t len = strlen(src);
|
|
|
|
size_t ret = len;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
if (len >= size)
|
|
|
|
len = size - 1;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
memcpy(dst, src, len);
|
|
|
|
dst[len] = '\0';
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
return ret;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:01:29 +08:00
|
|
|
#endif
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
#ifndef HAVE_STRLCAT
|
|
|
|
/*
|
|
|
|
* Function API taken from OpenBSD. Like strncat(), but does not 0 fill the
|
|
|
|
* buffer, and always NULL terminates the buffer. size is the length of the
|
|
|
|
* buffer, which should be one more than the maximum resulting string
|
|
|
|
* length.
|
|
|
|
*/
|
|
|
|
size_t strlcat(char *dst, const char *src, size_t size)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:01:29 +08:00
|
|
|
size_t len1 = strlen(dst);
|
|
|
|
size_t len2 = strlen(src);
|
|
|
|
size_t ret = len1 + len2;
|
|
|
|
|
|
|
|
if (len1 + len2 >= size)
|
|
|
|
len2 = size - len1 - 1;
|
|
|
|
if (len2 > 0) {
|
|
|
|
memcpy(dst + len1, src, len2);
|
|
|
|
dst[len1 + len2] = '\0';
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:01:29 +08:00
|
|
|
return ret;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:01:29 +08:00
|
|
|
#endif
|