src/3proxy.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++------ src/stringtable.c | 2 +- 2 files changed, 154 insertions(+), 19 deletions(-) diff --git a/src/3proxy.c b/src/3proxy.c index e3d0140..fc8f13d 100644 --- a/src/3proxy.c +++ b/src/3proxy.c @@ -13,6 +13,18 @@ #define DEFAULTCONFIG stringtable[20] #endif +// getopt +#ifndef _WIN32 +#include + +extern char *optarg; +extern int optind, opterr, optopt; + +#include +#include +#include +#endif + typedef int (*MAINFUNC)(int, char**); pthread_mutex_t bandlim_mutex; @@ -73,6 +85,54 @@ char *chrootp = NULL; #endif char * curconf = NULL; +// parse options +#ifndef __WIN32 +static int opt_daemon; +static char *opt_user = NULL; +static char *opt_group = NULL; +static char *opt_conffile = NULL; +static char *opt_pidfile = NULL; + +static int parse_cmdline(int argc, char **argv[]) + { + int opt = 0; + while(1) + { + opt = getopt(argc, argv, "du:g:c:p:"); + switch(opt) + { + case 'd': // daemonize + opt_daemon = 1; + break; + + case 'u': // username + opt_user = strdup(optarg); + break; + + case 'g': // groupname + opt_group = strdup(optarg); + break; + + case 'c': // config file + opt_conffile = strdup(optarg); + break; + + case 'p': // pidfile + opt_pidfile = strdup(optarg); + break; + + case ':': // option value not found + case '?': // option or value not found + return -1; + + } + + if(opt == -1) + return 0; + } + } +#endif + FILE * confopen(){ curconf = conffile; #ifndef _WIN32 @@ -288,6 +348,8 @@ void mysigterm (int sig){ pthread_mutex_unlock(&odbc_mutex); #endif timetoexit = 1; + if(opt_pidfile) + unlink(opt_pidfile); } #endif @@ -799,9 +861,8 @@ int readconfig(FILE * fp){ #endif continue; } - else if(!strcmp((char *)ch->argv[0], "daemon") && ch->argc == 1) { - if(!demon)daemonize(); - demon = 1; + else if(!strcmp((char *)ch->argv[0], "daemon") && ch->argc == 1) { + opt_daemon = 1; continue; } else if(!strcmp((char *)ch->argv[0], "writable") && ch->argc == 1) { @@ -1466,20 +1527,14 @@ int readconfig(FILE * fp){ continue; } #ifndef _WIN32 - else if(!strcmp((char *)ch->argv[0], "setuid") && ch->argc == 2) { - res = atoi((char *)ch->argv[1]); - if(!res || setuid(res)) { - fprintf(stderr, "Unable to set uid %d", res); - return(30); - } + else if(!strcmp((char *)ch->argv[0], "setuid") && ch->argc == 2) { + if(opt_user) free(opt_user); + opt_user = strdup((char *)ch->argv[1]); continue; } - else if(!strcmp((char *)ch->argv[0], "setgid") && ch->argc == 2) { - res = atoi((char *)ch->argv[1]); - if(!res || setgid(res)) { - fprintf(stderr, "Unable to set gid %d", res); - return(31); - } + else if(!strcmp((char *)ch->argv[0], "setgid") && ch->argc == 2) { + if(opt_group) free(opt_group); + opt_group = strdup((char *)ch->argv[1]); continue; } else if(!strcmp((char *)ch->argv[0], "chroot") && ch->argc == 2) { @@ -1639,25 +1694,104 @@ int main(int argc, char * argv[]) { } RETURN(0); } -#endif conffile = mystrdup((argc==2)?argv[1]:(char*)DEFAULTCONFIG); +#else + // parse options + if(parse_cmdline(argc, argv)) + { + fprintf(stderr, "parse option failed\n"); + return 1; + } + conffile = mystrdup(opt_conffile ? opt_conffile : (char *)DEFAULTCONFIG); +#endif if(conffile && *conffile != '-') { fp = confopen(); #ifndef _WIN32 if(!fp) fp = stdin; #endif } +#ifdef _WIN32 if(argc > 2 || !(fp)) { fprintf(stderr, "Usage: %s [conffile]\n", argv[0]); -#ifdef _WIN32 fprintf(stderr, "\n\t%s --install\n\tto install as service\n" "\n\t%s --remove\n\tto remove service\n", argv[0], argv[0]); -#endif fprintf(stderr, "\n%s", copyright); return 1; } +#endif + +#ifndef _WIN32 +// handle options + uid_t uid = 0; + gid_t gid = 0; + if(opt_user) + { + struct passwd *p; + + if(isdigit(opt_user[0])) + { + uid = atoi(opt_user); + p = getpwuid(uid); + } + else + p = getpwnam(opt_user); + if(!p) + { + fprintf(stderr, "user %s not found\n", opt_user); + return 1; + } + uid = p->pw_uid; + gid = p->pw_gid; + } + + if(opt_group) + { + struct group *p; + if(isdigit(opt_group[0])) + { + gid = atoi(opt_group); + p = getgrgid(gid); + } + else + p = getgrnam(opt_group); + if(!p) + { + fprintf(stderr, "group %s not found\n", opt_group); + return 1; + } + gid = p->gr_gid; + } + + if(gid && setgid(gid)) + { + fprintf(stderr, "setgid failed: %s\n", strerror(errno)); + return 1; + } + + if(uid && setuid(uid)) + { + fprintf(stderr, "setuid failed: %s\n", strerror(errno)); + return 1; + } + + if(opt_daemon) daemonize(); + demon = 1; + + if(opt_pidfile) + { + FILE *pidfile = fopen(opt_pidfile, "w"); + if(!pidfile) + { + fprintf(stderr, "open pidfile: %s\n", strerror(errno)); + return 1; + } + + fprintf(pidfile, "%d\n", getpid()); + fclose(pidfile); + } +#endif pthread_mutex_init(&acl_mutex, NULL); pthread_mutex_init(&bandlim_mutex, NULL); @@ -1690,6 +1824,7 @@ int main(int argc, char * argv[]) { #else signal(SIGCONT, mysigpause); signal(SIGTERM, mysigterm); + signal(SIGINT, mysigterm); signal(SIGUSR1, mysigusr1); signal(SIGPIPE, SIG_IGN); cyclestep(); diff --git a/src/stringtable.c b/src/stringtable.c index 082a6bd..e4c29d9 100644 --- a/src/stringtable.c +++ b/src/stringtable.c @@ -23,7 +23,7 @@ unsigned char * strings[] = { /* 19 */ NULL, #ifndef TPROXY_CONF #ifndef _WIN32 -/* 20 */ (unsigned char *)"/usr/local/etc/3proxy.cfg", +/* 20 */ (unsigned char *)"/etc/3proxy.conf", #else /* 20 */ (unsigned char *)"3proxy.cfg", #endif