2f2d74e9f2
heap overflow exploit.
276 lines
6.7 KiB
C
276 lines
6.7 KiB
C
/* $Id: utils.c,v 1.3 2001-01-15 17:06:19 rjkaes Exp $
|
|
*
|
|
* 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,
|
|
* the load cutoff routine is in here. Could not think of a better place for
|
|
* it, so it's in here.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "tinyproxy.h"
|
|
|
|
#include <ctype.h>
|
|
#include <signal.h>
|
|
#include <sysexits.h>
|
|
|
|
#include "buffer.h"
|
|
#include "log.h"
|
|
#include "sock.h"
|
|
#include "utils.h"
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
char *xstrstr(char *haystack, char *needle, size_t length,
|
|
bool_t case_sensitive)
|
|
{
|
|
unsigned int i;
|
|
/* Used to specify which function to use... need the decl. */
|
|
int (*fn) (const char *s1, const char *s2, size_t n);
|
|
|
|
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)
|
|
return (haystack + i);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Display an error to the client.
|
|
*/
|
|
int httperr(struct conn_s *connptr, int err, char *msg)
|
|
{
|
|
static char *premsg = "HTTP/1.0 %d %s\r\n" \
|
|
"Content-type: text/html\r\n\r\n" \
|
|
"<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" \
|
|
"<font size=\"-1\"><em>Generated by %s</em></font>\r\n" \
|
|
"</body></html>\r\n";
|
|
|
|
connptr->output_message = malloc(MAXBUFFSIZE);
|
|
if (!connptr->output_message) {
|
|
log(LOG_CRIT, "Out of memory!");
|
|
return -1;
|
|
}
|
|
|
|
snprintf(connptr->output_message, MAXBUFFSIZE, premsg, err, msg, msg, err, msg, VERSION);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void makedaemon(void)
|
|
{
|
|
if (fork() != 0)
|
|
exit(0);
|
|
|
|
setsid();
|
|
signal(SIGHUP, SIG_IGN);
|
|
|
|
if (fork() != 0)
|
|
exit(0);
|
|
|
|
chdir("/");
|
|
umask(077);
|
|
|
|
close(0);
|
|
close(1);
|
|
close(2);
|
|
}
|
|
|
|
/*
|
|
* Safely creates filename and returns the low-level file descriptor.
|
|
*/
|
|
static int create_file_safely(const char *filename)
|
|
{
|
|
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) {
|
|
log(LOG_ERR, "Error checking PID file %s: %s",
|
|
filename, strerror(errno));
|
|
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) {
|
|
log(LOG_ERR, "Could not create PID file %s: %s",
|
|
filename, strerror(errno));
|
|
return -1;
|
|
}
|
|
} else {
|
|
struct stat fstatinfo;
|
|
|
|
/*
|
|
* Open an existing file.
|
|
*/
|
|
if ((fildes = open(filename, O_RDWR)) < 0) {
|
|
log(LOG_ERR, "Could not open PID file %s: %s",
|
|
filename, strerror(errno));
|
|
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) {
|
|
log(LOG_ERR, "The PID file %s has been changed before it could be opened!",
|
|
filename);
|
|
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)) {
|
|
log(LOG_ERR, "The PID file %s has too many links, or is not a regular file: %s",
|
|
filename, strerror(errno));
|
|
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,
|
|
* and if you're using that you deserver what you get.
|
|
* ("Little sympathy has been extended")
|
|
*/
|
|
#if defined NO_FTRUNCATE
|
|
close(fildes);
|
|
if ((fildes = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
|
|
log(LOG_ERR, "Could not open PID file %s: %s",
|
|
filename, strerror(errno));
|
|
return -1;
|
|
}
|
|
#else
|
|
ftruncate(fildes, 0);
|
|
#endif /* NO_FTRUNCATE */
|
|
}
|
|
|
|
return fildes;
|
|
}
|
|
|
|
/*
|
|
* Write the PID of the program to the specified file.
|
|
*/
|
|
void pidfile_create(const char *filename)
|
|
{
|
|
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) {
|
|
log(LOG_ERR, "fdopen() error on PID file %s: %s",
|
|
filename, strerror(errno));
|
|
close(fildes);
|
|
unlink(filename);
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(fd, "%ld\n", (long)getpid());
|
|
fclose(fd);
|
|
}
|
|
|
|
#ifndef HAVE_STRLCPY
|
|
/*
|
|
* 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.
|
|
*/
|
|
size_t strlcpy(char *dst, const char *src, size_t size)
|
|
{
|
|
size_t len = strlen(src);
|
|
size_t ret = len;
|
|
|
|
if (len >= size)
|
|
len = size - 1;
|
|
|
|
memcpy(dst, src, len);
|
|
dst[len] = '\0';
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#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)
|
|
{
|
|
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';
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|