From 9f080da4887c8edcf91d68829838e32d7cda48f7 Mon Sep 17 00:00:00 2001 From: Robert James Kaes Date: Tue, 12 Sep 2000 00:03:53 +0000 Subject: Fixed the change user/group ability. Log when tinyproxy is using default values rather than specific ones. Cleaned up the command line arguments since tinyproxy now uses a configuration file. Removed the USR1 signal and added the thread creation code. --- src/tinyproxy.c | 518 ++++++++++++++++++++------------------------------------ src/tinyproxy.h | 104 +++++++----- 2 files changed, 246 insertions(+), 376 deletions(-) (limited to 'src') diff --git a/src/tinyproxy.c b/src/tinyproxy.c index e41d95e..496739f 100644 --- a/src/tinyproxy.c +++ b/src/tinyproxy.c @@ -1,6 +1,6 @@ -/* $Id: tinyproxy.c,v 1.3 2000-03-31 20:08:19 rjkaes Exp $ +/* $Id: tinyproxy.c,v 1.4 2000-09-12 00:03:53 rjkaes Exp $ * - * The initialize routine. Basically sets up all the initial stuff (logfile, + * The initialise routine. Basically sets up all the initial stuff (logfile, * listening socket, config options, etc.) and then sits there and loops * over the new connections until the daemon is closed. Also has additional * functions to handle the "user friendly" aspects of a program (usage, @@ -22,148 +22,55 @@ * General Public License for more details. */ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "tinyproxy.h" -#include -#include -#include +#include +#include #include -#include #include -#include -#include -#include -#include -#include -#include #include -#include -#include - -/* chris - need this for asynchronous DNS resolution */ -#include - -adns_state adns; -#include "config.h" -#include "tinyproxy.h" -#include "utils.h" -#include "log.h" -#include "sock.h" -#include "conns.h" -#include "reqs.h" +#include "anonymous.h" #include "buffer.h" #include "filter.h" -#include "anonymous.h" +#include "log.h" +#include "reqs.h" +#include "sock.h" +#include "stats.h" +#include "thread.h" +#include "utils.h" void takesig(int sig); +extern int yyparse(void); +extern FILE *yyin; + /* * Global Structures */ -struct config_s config = { - NULL, /* Log file handle */ - DEFAULT_LOG, /* Logfile name */ - FALSE, /* Use syslog instead? */ - DEFAULT_CUTOFFLOAD, /* Cut off load */ - DEFAULT_PORT, /* Listen on this port */ - DEFAULT_STATHOST, /* URL of stats host */ - FALSE, /* Quit? */ - DEFAULT_USER, /* Name of user to change to */ - FALSE, /* Run anonymous by default? */ - NULL, /* String containing the subnet allowed */ - NULL, /* IP address to listen on */ -#ifdef FILTER_ENABLE - NULL, /* Location of filter file */ -#endif /* FILTER_ENABLE */ - FALSE, /* Restrict the log to only errors */ -#ifdef XTINYPROXY - NULL, /* The name of this domain */ -#endif -#ifdef UPSTREAM_PROXY - NULL, /* name of the upstream proxy */ - 0, /* port of the upstream proxy */ -#endif -}; - -struct stat_s stats; +struct config_s config; float load = 0.00; -/* - * Dump info to the logfile - */ -static void dumpdebug(void) -{ - struct conn_s *connptr = connections; - long clients = 0, waiting = 0, relaying = 0, closing = 0, finished = 0; - - log("SIGUSR1 received, debug dump follows."); - - while (connptr) { - switch (connptr->type) { - case NEWCONN: - clients++; - break; - case WAITCONN: - waiting++; - break; - case RELAYCONN: - relaying++; - break; - case CLOSINGCONN: - closing++; - break; - case FINISHCONN: - finished++; - break; - default: - break; - } - connptr = connptr->next; - } - log("clients: %d, waiting: %d, relaying: %d," \ - "closing: %d, finished: %d", - clients, waiting, relaying, closing, finished); - log("total requests handled: %lu", stats.num_reqs); - log("total connections handled: %lu", stats.num_cons); - log("total sockets listened: %lu", stats.num_listens); - log("total sockets opened: %lu", stats.num_opens); - log("total bad opens: %lu", stats.num_badcons); - log("total bytes tx: %lu", stats.num_tx); - log("total bytes rx: %lu", stats.num_rx); - log("connections refused due to load: %lu", stats.num_refused); - log("garbage collections: %lu", stats.num_garbage); - log("idle connections killed: %lu", stats.num_idles); - log("end debug dump."); -} - /* * Handle a signal */ void takesig(int sig) { switch (sig) { - case SIGUSR1: - dumpdebug(); - break; case SIGHUP: if (config.logf) ftruncate(fileno(config.logf), 0); - log("SIGHUP received, cleaning up..."); - conncoll(); - garbcoll(); + log(LOG_NOTICE, "SIGHUP received, cleaning up..."); #ifdef FILTER_ENABLE if (config.filter) { filter_destroy(); filter_init(); } - log("Re-reading filter file."); + log(LOG_NOTICE, "Re-reading filter file."); #endif /* FILTER_ENABLE */ - log("Finished cleaning memory/connections."); + log(LOG_NOTICE, "Finished cleaning memory/connections."); break; case SIGTERM: #ifdef FILTER_ENABLE @@ -171,10 +78,7 @@ void takesig(int sig) filter_destroy(); #endif /* FILTER_ENABLE */ config.quit = TRUE; - break; - case SIGALRM: - calcload(); - alarm(LOAD_RECALCTIMER); + log(LOG_INFO, "SIGTERM received."); break; } if (sig != SIGTERM) @@ -183,57 +87,44 @@ void takesig(int sig) } /* - * Display usage to the user on stderr. + * Display the version information for the user. + */ +static void versiondisp(void) +{ + printf("tinyproxy " VERSION "\n"); + printf("\ +Copyright 1998 Steven Young (sdyoung@well.com)\n\ +Copyright 1998-2000 Robert James Kaes (rjkaes@flarenet.com)\n\ +Copyright 2000 Chris Lightfoot (chris@ex-parrot.com)\n\ +\n\ +This program is free software; you can redistribute it and/or modify it\n\ +under the terms of the GNU General Public License as published by the Free\n\ +Software Foundation; either version 2, or (at your option) any later\n\ +version.\n\ +\n\ +This program is distributed in the hope that it will be useful, but WITHOUT\n\ +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n\ +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n\ +more details.\n"); +} + +/* + * Display usage to the user. */ static void usagedisp(void) { - printf("tinyproxy version " VERSION "\n"); - printf("Copyright 1998 Steven Young (sdyoung@well.com)\n"); - printf - ("Copyright 1998-1999 Robert James Kaes (rjkaes@flarenet.com)\n\n"); - printf("Copyright 2000 Chris Lightfoot (chris@ex-parrot.com)\n"); - - printf - ("This software is licensed under the GNU General Public License (GPL).\n"); - printf("See the file 'COPYING' included with tinyproxy source.\n\n"); - - printf("Compiled with Ian Jackson's adns:\n"); - printf(" http://www.chiark.greenend.org.uk/~ian/adns/\n\n"); - - printf("Usage: tinyproxy [args]\n"); - printf("Options:\n"); - printf("\t-a header\tallow 'header' through the anon block\n"); - printf("\t-d\t\tdo not daemonize\n"); -#ifdef FILTER_ENABLE - printf("\t-f filterfile\tblock sites specified in filterfile\n"); -#endif /* FILTER_ENABLE */ - printf("\t-h\t\tdisplay usage\n"); - printf("\t-i ip_address\tonly listen on this address\n"); - printf("\t-l logfile\tlog to 'logfile'\n"); - printf - ("\t-n ip_address\tallow access from only this subnet. (i.e. 192.168.0.)\n"); - printf("\t-p port\t\tlisten on 'port'\n"); - printf("\t-r\t\trestrict the log to only errors\n"); - printf("\t-s stathost\tset stathost to 'stathost'\n"); -#ifdef HAVE_SYSLOG_H - printf("\t-S\t\tlog using the syslog instead\n"); -#endif -#ifdef UPSTREAM_PROXY - printf("\t-t domain:port\tredirect connections to an upstream proxy\n"); -#endif - printf("\t-u user\t\tchange to user after startup. \"\" disables\n"); - printf("\t-v\t\tdisplay version number\n"); - printf - ("\t-w load\t\tstop accepting new connections at 'load'. 0 disables\n"); -#ifdef XTINYPROXY - printf - ("\t-x domain\tAdd a XTinyproxy header with the peer's IP address\n"); -#endif - /* UPSTREAM_PROXY */ + printf("\ +Usage: tinyproxy [options]\n\ +Options:\n\ + -d Operate in DEBUG mode.\n\ + -c FILE Use an alternate configuration file.\n\ + -h Display this usage information.\n\ + -v Display the version number.\n"); + /* Display the modes compiled into tinyproxy */ printf("\nFeatures Compiled In:\n"); -#ifdef XTINYPROXY +#ifdef XTINYPROXY_ENABLE printf(" XTinyproxy Header\n"); #endif /* XTINYPROXY */ #ifdef FILTER_ENABLE @@ -243,157 +134,59 @@ static void usagedisp(void) #ifndef NDEBUG printf(" Debuggin code\n"); #endif /* NDEBUG */ -#ifdef UPSTREAM_PROXY - printf(" Upstream proxy\n"); -#endif /* UPSTREAM_PROXY */ +#ifdef TUNNEL_SUPPORT + printf(" TCP Tunneling\n"); +#endif /* TUNNEL_SUPPORT */ } int main(int argc, char **argv) { int optch; - flag usage = FALSE, godaemon = TRUE, changeid = FALSE; + bool_t godaemon = TRUE; struct passwd *thisuser = NULL; + struct group *thisgroup = NULL; + char *conf_file = DEFAULT_CONF_FILE; -#ifdef UPSTREAM_PROXY - char *upstream_ptr; -#endif /* UPSTREAM_PROXY */ - - while ((optch = getopt(argc, argv, "vh?dp:l:Sa:w:s:u:n:i:rx:f:t:")) != + while ((optch = getopt(argc, argv, "c:vdh")) != EOF) { switch (optch) { case 'v': - fprintf(stderr, "tinyproxy version " VERSION "\n"); + versiondisp(); exit(EX_OK); - break; - case 'p': - if (!(config.port = atoi(optarg))) { - log - ("bad port on commandline, defaulting to %d", - DEFAULT_PORT); - config.port = DEFAULT_PORT; - } - break; - case 'l': - if (!(config.logf_name = xstrdup(optarg))) { - log("bad log file, defaulting to %s", - DEFAULT_LOG); - config.logf_name = DEFAULT_LOG; - } - break; -#ifdef HAVE_SYSLOG_H - case 'S': /* Use the syslog function to handle logging */ - config.syslog = TRUE; - break; -#endif case 'd': godaemon = FALSE; break; - case 'w': - sscanf(optarg, "%f", &config.cutoffload); - break; - case 's': - if (!(config.stathost = xstrdup(optarg))) { - log("bad stathost, defaulting to %s", - DEFAULT_STATHOST); - config.stathost = DEFAULT_STATHOST; - } - break; - case 'u': - if (!(config.changeuser = xstrdup(optarg))) { - log("bad user name, defaulting to %s", - DEFAULT_USER); - config.changeuser = DEFAULT_USER; - } - break; - case 'a': - config.anonymous = TRUE; - anon_insert(optarg); - break; - case 'n': - if (!(config.subnet = xstrdup(optarg))) { - log("tinyproxy: could not allocate memory"); - exit(EX_SOFTWARE); - } - break; - case 'i': - if (!(config.ipAddr = xstrdup(optarg))) { - log("tinyproxy: could not allocate memory"); - exit(EX_SOFTWARE); - } - break; -#ifdef FILTER_ENABLE - case 'f': - if (!(config.filter = xstrdup(optarg))) { - log("tinyproxy: could not allocate memory"); - } - break; -#endif /* FILTER_ENABLE */ - case 'r': - config.restricted = TRUE; - break; -#ifdef XTINYPROXY - case 'x': - if (!(config.my_domain = xstrdup(optarg))) { - log("tinyproxy: could not allocate memory"); - exit(EX_SOFTWARE); - } - break; -#endif - -#ifdef UPSTREAM_PROXY - case 't': - if (!(upstream_ptr = strchr(optarg, ':'))) { - log("tinyproxy: invalid UPSTREAM declaration"); - break; - } - - *upstream_ptr++ = '\0'; - if (!(config.upstream_name = xstrdup(optarg))) { - log("tinyproxy: could not allocate memory"); + case 'c': + conf_file = strdup(optarg); + if (!conf_file) { + log(LOG_EMERG, "tinyproxy: could not allocate memory"); exit(EX_SOFTWARE); } - config.upstream_port = atoi(upstream_ptr); -#ifndef NDEBUG - log("upstream name: %s", config.upstream_name); - log("upstream port: %d", config.upstream_port); -#endif /* NDEBUG */ - break; -#endif /* UPSTREAM_PROXY */ - - case '?': case 'h': default: - usage = TRUE; - break; + usagedisp(); + exit(EX_OK); } } - if (usage == TRUE) { - usagedisp(); - exit(EX_OK); - } - /* - * If ANONYMOUS is turned on, make sure that Content-Length is - * in the list of allowed headers, since it is required in a - * HTTP/1.0 request. Also add the Content-Type header since it goes - * hand in hand with Content-Length. - * - rjkaes + * Read in the settings from the config file. */ - if (config.anonymous) { - anon_insert("Content-Length:"); - anon_insert("Content-Type:"); - } - - /* chris - Initialise asynchronous DNS */ - if (adns_init(&adns, 0, 0)) { - log("tinyproxy: could not initialise ADNS"); + yyin = fopen(conf_file, "r"); + if (!yyin) { + log(LOG_ERR, "Could not open %s file", conf_file); exit(EX_SOFTWARE); } + yyparse(); /* Open the log file if not using syslog */ if (config.syslog == FALSE) { + if (!config.logf_name) { + log(LOG_INFO, "Setting Logfile to \"%s\"", DEFAULT_LOG); + config.logf_name = DEFAULT_LOG; + } + if (!(config.logf = fopen(config.logf_name, "a"))) { fprintf(stderr, "Unable to open logfile %s for appending!\n", @@ -407,72 +200,129 @@ int main(int argc, char **argv) openlog("tinyproxy", LOG_PID, LOG_USER); } - log(PACKAGE " " VERSION " starting..."); - - if (strlen(config.changeuser)) { - if ((getuid() != 0) && (geteuid() != 0)) { - log - ("not running as root, therefore not changing uid/gid."); - } else { - changeid = TRUE; - if (!(thisuser = getpwnam(config.changeuser))) { - log("unable to find user \"%s\"!", - config.changeuser); - exit(EX_NOUSER); - } - log("changing to user \"%s\" (%d/%d).", - config.changeuser, thisuser->pw_uid, - thisuser->pw_gid); - } + log(LOG_INFO, PACKAGE " " VERSION " starting..."); + + /* + * Set the default values if they were not set in the config file. + */ + if (config.port == 0) { + log(LOG_INFO, "Setting Port to %u", DEFAULT_PORT); + config.port = DEFAULT_PORT; } -#ifdef NDEBUG + if (!config.stathost) { + log(LOG_INFO, "Setting stathost to \"%s\"", DEFAULT_STATHOST); + config.stathost = DEFAULT_STATHOST; + } + if (!config.username) { + log(LOG_INFO, "Setting user to \"%s\"", DEFAULT_USER); + config.username = DEFAULT_USER; + } + if (config.idletimeout == 0) { + log(LOG_INFO, "Setting idle timeout to %u seconds", MAX_IDLE_TIME); + config.idletimeout = MAX_IDLE_TIME; + } + + init_stats(); + + /* + * If ANONYMOUS is turned on, make sure that Content-Length is + * in the list of allowed headers, since it is required in a + * HTTP/1.0 request. Also add the Content-Type header since it goes + * hand in hand with Content-Length. + * - rjkaes + */ + if (config.anonymous) { + anon_insert("Content-Length:"); + anon_insert("Content-Type:"); + } + if (godaemon == TRUE) makedaemon(); -#else - printf("Debugging is enabled, so you can not go daemon.\n"); -#endif + + if (config.pidpath) { + pidfile_create(config.pidpath); + } if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { - fprintf(stderr, "Could not set SIGPIPE\n"); + log(LOG_EMERG, "Could not set SIGPIPE\n"); exit(EX_OSERR); } - if (signal(SIGUSR1, takesig) == SIG_ERR) { - fprintf(stderr, "Could not set SIGUSR1\n"); + +#ifdef FILTER_ENABLE + if (config.filter) + filter_init(); +#endif /* FILTER_ENABLE */ + + /* + * Start listening on the selected port. + */ + if (thread_listening_sock(config.port) < 0) { + log(LOG_EMERG, "Problem creating listening socket"); exit(EX_OSERR); } + + /* + * Switch to a different user. + */ + if (geteuid() == 0) { + if (config.group && strlen(config.group) > 0) { + thisgroup = getgrnam(config.group); + if (!thisgroup) { + log(LOG_ERR, "Unable to find group '%s'!", config.group); + exit(EX_NOUSER); + } + if (setgid(thisgroup->gr_gid) < 0) { + log(LOG_ERR, "Unable to change to group '%s'", config.group); + exit(EX_CANTCREAT); + } + log(LOG_INFO, "Now running as group %s", config.group); + } + if (config.username && strlen(config.username) > 0) { + thisuser = getpwnam(config.username); + if (!thisuser) { + log(LOG_ERR, "Unable to find user '%s'!", config.username); + exit(EX_NOUSER); + } + if (setuid(thisuser->pw_uid) < 0) { + log(LOG_ERR, "Unable to change to user '%s'", config.username); + exit(EX_CANTCREAT); + } + log(LOG_INFO, "Now running as user %s", config.username); + } + } else { + log(LOG_WARNING, "Not running as root, so not changing UID/GID."); + } + + if (thread_pool_create() < 0) { + log(LOG_ERR, "Could not create the pool of threads"); + exit(EX_SOFTWARE); + } + + /* + * These signals are only for the main thread. + */ + log(LOG_INFO, "Setting the various signals."); if (signal(SIGTERM, takesig) == SIG_ERR) { - fprintf(stderr, "Could not set SIGTERM\n"); + log(LOG_EMERG, "Could not set SIGTERM\n"); exit(EX_OSERR); } if (signal(SIGHUP, takesig) == SIG_ERR) { - fprintf(stderr, "Could not set SIGHUP\n"); - exit(EX_OSERR); - } - if (signal(SIGALRM, takesig) == SIG_ERR) { - fprintf(stderr, "Could not set SIGALRM\n"); + log(LOG_EMERG, "Could not set SIGHUP\n"); exit(EX_OSERR); } - alarm(LOAD_RECALCTIMER); - calcload(); - if (init_listen_sock(config.port) < 0) { - log("unable to bind port %d!", config.port); - exit(EX_UNAVAILABLE); - } - if (changeid == TRUE) { - setuid(thisuser->pw_uid); - setgid(thisuser->pw_gid); - } - log("now accepting connections."); + log(LOG_INFO, "Starting main loop. Accepting connections."); + thread_main_loop(); -#ifdef FILTER_ENABLE - if (config.filter) - filter_init(); -#endif /* FILTER_ENABLE */ + log(LOG_INFO, "Shutting down."); + thread_close_sock(); - while (config.quit == FALSE) { - if (getreqs() < 0) - break; + /* + * Remove the PID file. + */ + if (unlink(config.pidpath) < 0) { + log(LOG_WARNING, "Could not remove PID file %s: %s", + config.pidpath, strerror(errno)); } #ifdef FILTER_ENABLE @@ -480,16 +330,10 @@ int main(int argc, char **argv) filter_destroy(); #endif /* FILTER_ENABLE */ - log("shutting down."); - de_init_listen_sock(); - if (config.syslog == FALSE) fclose(config.logf); else closelog(); - /* finsih up ADNS */ - adns_finish(adns); - exit(EX_OK); } diff --git a/src/tinyproxy.h b/src/tinyproxy.h index 041c80f..0f9a0d8 100644 --- a/src/tinyproxy.h +++ b/src/tinyproxy.h @@ -1,4 +1,4 @@ -/* $Id: tinyproxy.h,v 1.3 2000-03-31 20:08:19 rjkaes Exp $ +/* $Id: tinyproxy.h,v 1.4 2000-09-12 00:03:53 rjkaes Exp $ * * See 'tinyproxy.c' for a detailed description. * @@ -16,70 +16,96 @@ * General Public License for more details. */ -#ifndef _TINYPROXY_H_ -#define _TINYPROXY_H_ 1 +#ifndef _TINYPROXY_TINYPROXY_H_ +#define _TINYPROXY_TINYPROXY_H_ #ifdef HAVE_CONFIG_H -#include +# include "../config.h" #endif -#include -#include +/* + * Include standard headers which are used through-out tinyproxy + */ +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_H +# include +#endif +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#include -#include "config.h" +#ifndef SHUT_RD /* these three Posix.1g names are quite new */ +# define SHUT_RD 0 /* shutdown for reading */ +# define SHUT_WR 1 /* shutdown for writing */ +# define SHUT_RDWR 2 /* shutdown for reading and writing */ +#endif /* Global variables for the main controls of the program */ -#define BUFFER (1024 * 2) /* Size of buffer for reading */ -#define MAXLISTEN 128 /* Max number of connections to listen for */ +#define MAXBUFFSIZE (1024 * 48) /* Max size of buffer */ +#define MAXLISTEN 1024 /* Max number of connections */ +#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */ -/* Make a new type: flag */ -typedef char flag; +/* Useful function macros */ +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) -/* Other stuff */ -#define FALSE (0) -#define TRUE (!FALSE) +/* Make a new type: bool_t */ +typedef enum { + FALSE = 0, + TRUE = (!FALSE) +} bool_t; struct config_s { FILE *logf; char *logf_name; - flag syslog; - float cutoffload; + bool_t syslog; int port; char *stathost; - flag quit; - char *changeuser; - flag anonymous; - char *subnet; + bool_t quit; + char *username; + char *group; + bool_t anonymous; char *ipAddr; #ifdef FILTER_ENABLE char *filter; #endif /* FILTER_ENABLE */ - flag restricted; -#ifdef XTINYPROXY +#ifdef XTINYPROXY_ENABLE char *my_domain; #endif -#ifdef UPSTREAM_PROXY - char *upstream_name; - int upstream_port; -#endif +#ifdef TUNNEL_SUPPORT + char *tunnel_name; + int tunnel_port; +#endif /* TUNNEL_SUPPORT */ + char *pidpath; + unsigned int idletimeout; }; -struct stat_s { - unsigned long int num_reqs; - unsigned long int num_cons; - unsigned long int num_badcons; - unsigned long int num_opens; - unsigned long int num_listens; - unsigned long int num_tx; - unsigned long int num_rx; - unsigned long int num_garbage; - unsigned long int num_idles; - unsigned long int num_refused; +struct conn_s { + int client_fd, server_fd; + struct buffer_s *cbuffer, *sbuffer; + bool_t simple_req; + char *output_message; }; /* Global Structures used in the program */ extern struct config_s config; -extern struct stat_s stats; -extern float load; #endif -- cgit v1.2.3