/*
3APA3A simpliest proxy server
(c) 2002-2006 by ZARAZA <3APA3A@security.nnov.ru>
please read License Agreement
$Id: 3proxy.c,v 1.51 2006/03/10 19:25:45 vlad Exp $
*/
#include "proxy.h"
#ifndef DEFAULTCONFIG
#define DEFAULTCONFIG stringtable[20]
#endif
typedef int (*MAINFUNC)(int, char**);
pthread_mutex_t bandlim_mutex;
pthread_mutex_t tc_mutex;
pthread_mutex_t hash_mutex;
pthread_mutex_t acl_mutex;
#ifndef NOODBC
pthread_mutex_t odbc_mutex;
#endif
int readconfig(FILE * fp);
int haveerror = 0;
int linenum = 0;
int needreload = 0;
time_t basetime = 0;
char * conffile = NULL;
struct counter_header {
unsigned char sig[4];
time_t updated;
} cheader = {"3CF", (time_t)0};
struct counter_record {
unsigned long traf;
unsigned long trafgb;
time_t cleared;
time_t updated;
} crecord;
struct child {
int argc;
unsigned char **argv;
};
int udpmainfunc (int argc, char** argv);
int tcpmainfunc (int argc, char** argv);
struct proxydef childdef = {NULL, 0, 0, S_NOSERVICE, ""};
#define STRINGBUF 65535
#define NPARAMS 4096
time_t logtime = 0, t = 0;
unsigned char tmpbuf[1024];
int bandlim_mutex_inited = 0;
FILE *writable;
extern unsigned char *strings[];
#ifndef _WIN32
char *chrootp = NULL;
#endif
char * curconf = NULL;
FILE * confopen(){
curconf = conffile;
#ifndef _WIN32
if(chrootp){
if(strstr(curconf, chrootp) == curconf)
curconf += strlen(chrootp);
}
#endif
if(writable) {
rewind(writable);
return writable;
}
return fopen(curconf, "r");
}
static void * itfree(void *data, void * retval){
myfree(data);
return retval;
}
void clearall(){
struct bandlim * bl;
struct bandlim * blout;
struct trafcount * tc;
struct passwords *pw;
struct ace *ac;
struct ace *acls[256];
struct iplist *ipl;
struct portlist *pl;
struct userlist *ul;
struct chain *ch;
struct filemon *fm;
int counterd, archiverc;
unsigned char *logname;
unsigned char **archiver;
int i;
pthread_mutex_lock(&bandlim_mutex);
bl = conf.bandlimiter;
blout = conf.bandlimiterout;
conf.bandlimiter = NULL;
conf.bandlimiterout = NULL;
pthread_mutex_unlock(&bandlim_mutex);
pthread_mutex_lock(&tc_mutex);
tc = conf.trafcounter;
conf.trafcounter = NULL;
pthread_mutex_unlock(&tc_mutex);
counterd = conf.counterd;
conf.counterd = -1;
logname = conf.logname;
conf.logname = NULL;
archiverc = conf.archiverc;
conf.archiverc = 0;
archiver = conf.archiver;
conf.archiver = NULL;
fm = conf.fmon;
conf.fmon = NULL;
pthread_mutex_lock(&acl_mutex);
for(i = 0; i < 256; i++) {
acls[i] = conf.acls[i];
conf.acls[i] = NULL;
}
pw = conf.pwl;
conf.pwl = NULL;
pthread_mutex_unlock(&acl_mutex);
conf.rotate = 0;
conf.logtype = NONE;
conf.countertype = NONE;
conf.aclnum = 0;
logtime = t = 0;
conf.authfunc = doconnect;
conf.bandlimfunc = NULL;
conf.intip = conf.extip = 0;
conf.intport = conf.extport = 0;
conf.singlepacket = 0;
conf.maxchild = 100;
resolvfunc = NULL;
usleep(SLEEPTIME);
for(; bl; bl = (struct bandlim *) itfree(bl, bl->next));
for(; blout; blout = (struct bandlim *) itfree(blout, blout->next));
for(; tc; tc = (struct trafcount *) itfree(tc, tc->next));
for(; pw; pw = (struct passwords *)itfree(pw, pw->next)){
if(pw->user) myfree(pw->user);
}
for(; fm; fm = (struct filemon *)itfree(fm, fm->next)){
if(fm->path) myfree(fm->path);
}
if(counterd != -1) {
close(counterd);
}
if(logname) {
myfree(logname);
}
if(archiver) {
for(i = 0; i < archiverc; i++) myfree(archiver[i]);
myfree(archiver);
}
for(i = 0; i < 256; i++) {
for(ac = acls[i]; ac; ac = (struct ace *) itfree(ac, ac->next)){
for(ipl = ac->src; ipl; ipl = (struct iplist *)itfree(ipl, ipl->next));
for(ipl = ac->dst; ipl; ipl = (struct iplist *)itfree(ipl,ipl->next));
for(pl = ac->ports; pl; pl = (struct portlist *)itfree(pl, pl->next));
for(ul = ac->users; ul && ul->next; ul = ul->next);
if(ul) myfree(ul);
for(ch = ac->chains; ch; ch = (struct chain *) itfree(ch, ch->next)){
if(ch->extuser) myfree(ch->extuser);
if(ch->extpass) myfree(ch->extpass);
}
}
}
}
#ifdef _WIN32
OSVERSIONINFO osv;
int service = 0;
void cyclestep(void);
SERVICE_STATUS_HANDLE hSrv;
DWORD dwCurrState;
int SetStatus( DWORD dwState, DWORD dwExitCode, DWORD dwProgress )
{
SERVICE_STATUS srvStatus;
srvStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
srvStatus.dwCurrentState = dwCurrState = dwState;
srvStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
srvStatus.dwWin32ExitCode = dwExitCode;
srvStatus.dwServiceSpecificExitCode = 0;
srvStatus.dwCheckPoint = dwProgress;
srvStatus.dwWaitHint = 3000;
return SetServiceStatus( hSrv, &srvStatus );
}
void __stdcall CommandHandler( DWORD dwCommand )
{
FILE *fp;
int error;
switch( dwCommand )
{
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
SetStatus( SERVICE_STOP_PENDING, 0, 1 );
paused++;
timetoexit = 1;
Sleep(2000);
SetStatus( SERVICE_STOPPED, 0, 0 );
#ifndef NOODBC
pthread_mutex_lock(&odbc_mutex);
close_sql();
pthread_mutex_unlock(&odbc_mutex);
#endif
break;
case SERVICE_CONTROL_PAUSE:
SetStatus( SERVICE_PAUSE_PENDING, 0, 1 );
paused++;
SetStatus( SERVICE_PAUSED, 0, 0 );
break;
case SERVICE_CONTROL_CONTINUE:
SetStatus( SERVICE_CONTINUE_PENDING, 0, 1 );
clearall();
fp = confopen();
if(fp){
error = readconfig(fp);
if(error) {
clearall();
}
if(!writable)fclose(fp);
}
SetStatus( SERVICE_RUNNING, 0, 0 );
break;
default: ;
}
}
void __stdcall ServiceMain(int argc, unsigned char* argv[] )
{
hSrv = RegisterServiceCtrlHandler(stringtable[1], (LPHANDLER_FUNCTION)CommandHandler);
if( hSrv == 0 ) return;
SetStatus( SERVICE_START_PENDING, 0, 1 );
SetStatus( SERVICE_RUNNING, 0, 0 );
cyclestep();
}
#else
void mysigusr1 (int sig){
needreload = 1;
}
int even = 0;
void mysigpause (int sig){
paused++;
even = !even;
if(!even){
needreload = 1;
}
}
void mysigterm (int sig){
paused++;
usleep(2000*SLEEPTIME);
#ifndef NOODBC
pthread_mutex_lock(&odbc_mutex);
close_sql();
pthread_mutex_unlock(&odbc_mutex);
#endif
timetoexit = 1;
}
#endif
int reload (void){
FILE *fp;
int error = -2;
paused++;
clearall();
paused++;
fp = confopen();
if(fp){
error = readconfig(fp);
if(error) {
clearall();
}
if(!writable)fclose(fp);
}
return error;
}
#ifdef _WIN32
DWORD WINAPI startsrv(LPVOID data) {
#else
void * startsrv(void * data) {
#endif
struct child *d = (struct child *)data;
if(childdef.isudp) udpmainfunc(d->argc, (char **)d->argv);
else tcpmainfunc(d->argc, (char **)d->argv);
return 0;
}
int included =0;
int parsestr (unsigned char *str, unsigned char **argm, int nitems, unsigned char * buf, int *inbuf, int *bufsize){
int argc = 0;
int space = 1;
int comment = 0;
unsigned char * incbegin = 0;
int fd;
int res, len;
int i = 1;
unsigned char *str1;
for(;;str++){
if(*str == '\"'){
str1 = str;
do {
*str1 = *(str1 + 1);
}while(*(str1++));
if(!comment || *str != '\"'){
comment = !comment;
}
}
switch(*str){
case '\0':
if(comment) return -1;
argm[argc] = 0;
return argc;
case '$':
if(!comment && !included){
incbegin = str;
*str = 0;
}
break;
case '\r':
case '\n':
case '\t':
case ' ':
if(!comment){
*str = 0;
space = 1;
i = 0;
if(incbegin){
argc--;
if((fd = open((char *)incbegin+1, O_RDONLY)) <= 0){
fprintf(stderr, "Failed to open %s\n", incbegin+1);
break;
}
if((*bufsize - *inbuf) <STRINGBUF){
*bufsize += STRINGBUF;
if(!(buf = myrealloc(buf, *bufsize))){
fprintf(stderr, "Failed to allocate memory for %s\n", incbegin+1);
close(fd);
break;
}
}
len = 0;
if(argm[argc]!=(incbegin+1)) {
len = strlen((char *)argm[argc]);
memcpy(buf+*inbuf, argm[argc], len);
}
if((res = read(fd, buf+*inbuf+len, STRINGBUF-(1+len))) <= 0) {
perror(incbegin+1);
close(fd);
break;
}
close(fd);
buf[*inbuf+res+len] = 0;
incbegin = buf + *inbuf;
(*inbuf) += (res + len + 1);
included++;
argc+=parsestr(incbegin, argm + argc, nitems - argc, buf, inbuf, bufsize);
included--;
incbegin = NULL;
}
break;
}
default:
i++;
if(space) {
space = 0;
argm[argc++] = str;
if(argc >= nitems) return argc;
}
}
}
}
unsigned char * dologname (unsigned char *buf, const unsigned char *name, const unsigned char *ext, ROTATION lt, time_t t) {
struct tm *ts;
ts = localtime(&t);
switch(lt){
case NONE:
sprintf((char *)buf, "%s", name);
break;
case ANNUALLY:
sprintf((char *)buf, "%s.%04d", name, ts->tm_year+1900);
break;
case MONTHLY:
sprintf((char *)buf, "%s.%04d.%02d", name, ts->tm_year+1900, ts->tm_mon+1);
break;
case WEEKLY:
t = t - (ts->tm_wday * (60*60*24));
ts = localtime(&t);
sprintf((char *)buf, "%s.%04d.%02d.%02d", name, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday);
break;
case DAILY:
sprintf((char *)buf, "%s.%04d.%02d.%02d", name, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday);
break;
case HOURLY:
sprintf((char *)buf, "%s.%04d.%02d.%02d-%02d", name, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday, ts->tm_hour);
break;
case MINUTELY:
sprintf((char *)buf, "%s.%04d.%02d.%02d-%02d.%02d", name, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
break;
default:
break;
}
if(ext){
strcat((char *)buf, ".");
strcat((char *)buf, (char *)ext);
}
return buf;
}
int wday = 0;
int timechanged (time_t oldtime, time_t newtime, ROTATION lt){
struct tm tmold;
struct tm *tm;
tm = localtime(&oldtime);
memcpy(&tmold, tm, sizeof(tmold));
tm = localtime(&newtime);
switch(lt){
case MINUTELY:
if(tm->tm_min != tmold.tm_min)return 1;
break;
case HOURLY:
if(tm->tm_hour != tmold.tm_hour)return 1;
break;
case DAILY:
if(tm->tm_yday != tmold.tm_yday)return 1;
break;
case MONTHLY:
if(tm->tm_mon != tmold.tm_mon)return 1;
break;
case ANNUALLY:
if(tm->tm_year != tmold.tm_year)return 1;
break;
case WEEKLY:
if(((newtime - oldtime) > (60*60*24*7))
|| tm->tm_wday < tmold.tm_wday
|| (tm->tm_wday == tmold.tm_wday && (newtime - oldtime) > (60*60*24*6))
)return 1;
break;
default:
break;
}
return 0;
}
void cyclestep(void){
struct tm *tm;
time_t minutecounter;
minutecounter = time(0);
for(;;){
usleep(SLEEPTIME*1000);
if(needreload) {
reload();
needreload = 0;
}
t = time(0);
fflush(stdlog);
if(timechanged(minutecounter, t, MINUTELY)) {
struct filemon *fm;
struct stat sb;
for(fm=conf.fmon; fm; fm=fm->next){
if(!stat(fm->path, &sb)){
if(fm->sb.st_mtime != sb.st_mtime || fm->sb.st_size != sb.st_size){
stat(fm->path, &fm->sb);
needreload = 1;
}
}
}
}
if(timechanged(basetime, t, DAILY)) {
tm = localtime(&t);
wday = (1 << tm->tm_wday);
tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
basetime = mktime(tm);
}
if(conf.logname) {
if(timechanged(logtime, t, conf.logtype)) {
FILE *fp, *fp1;
fp = fopen((char *)dologname (tmpbuf, conf.logname, NULL, conf.logtype, t), "a");
if (fp) {
fp1 = stdlog;
stdlog = fp;
if(fp1) fclose(fp1);
}
fseek(stdout, 0L, SEEK_END);
usleep(SLEEPTIME);
logtime = t;
if(conf.logtype != NONE && conf.rotate) {
t = 1;
switch(conf.logtype){
case ANNUALLY:
t = t * 12;
case MONTHLY:
t = t * 4;
case WEEKLY:
t = t * 7;
case DAILY:
t = t * 24;
case HOURLY:
t = t * 60;
case MINUTELY:
t = t * 60;
default:
break;
}
dologname (tmpbuf, conf.logname, (conf.archiver)?conf.archiver[1]:NULL, conf.logtype, (logtime - t*conf.rotate));
remove ((char *) tmpbuf);
if(conf.archiver) {
int i;
*tmpbuf = 0;
for(i = 2; i < conf.archiverc && strlen((char *)tmpbuf) < 512; i++){
strcat((char *)tmpbuf, " ");
if(!strcmp((char *)conf.archiver[i], "%A")){
strcat((char *)tmpbuf, "\"");
dologname (tmpbuf + strlen((char *)tmpbuf), conf.logname, conf.archiver[1], conf.logtype, (logtime - t));
strcat((char *)tmpbuf, "\"");
}
else if(!strcmp((char *)conf.archiver[i], "%F")){
strcat((char *)tmpbuf, "\"");
dologname (tmpbuf+strlen((char *)tmpbuf), conf.logname, NULL, conf.logtype, (logtime-t));
strcat((char *)tmpbuf, "\"");
}
else
strcat((char *)tmpbuf, (char *)conf.archiver[i]);
}
system((char *)tmpbuf+1);
}
}
}
}
if(conf.counterd >= 0) {
time(&t);
if(timechanged(cheader.updated, t, MINUTELY)){
struct trafcount *tl;
if(conf.countertype && timechanged(cheader.updated, t, conf.countertype)){
FILE * cfp;
cfp = fopen((char *)dologname(tmpbuf, (unsigned char *)conf.counterfile, NULL, conf.countertype, t), "w");
if(cfp){
for(tl = conf.trafcounter; cfp && tl; tl = tl->next){
if(tl->type >= conf.countertype)
fprintf(cfp, "%05d %010lu %010lu%s%s\n", tl->number, tl->trafgb, tl->traf, tl->comment?" #" : "", tl->comment? tl->comment : "");
}
fclose(cfp);
}
}
for(tl = conf.trafcounter; tl; tl = tl->next){
if(tl->number){
if(tl->type!=NEVER && timechanged(tl->cleared, t, tl->type)){
tl->cleared = t;
tl->traf = 0;
tl->trafgb = 0;
}
lseek(conf.counterd,
sizeof(struct counter_header) + (tl->number - 1) * sizeof(struct counter_record),
SEEK_SET);
crecord.traf = tl->traf;
crecord.trafgb = tl->trafgb;
crecord.cleared = tl->cleared;
crecord.updated = tl->updated;
write(conf.counterd, &crecord, sizeof(struct counter_record));
}
}
cheader.updated = t;
lseek(conf.counterd, 0, SEEK_SET);
write(conf.counterd, &cheader, sizeof(struct counter_header));
}
}
if(timetoexit){
paused++;
usleep(SLEEPTIME*3000);
return;
}
}
}
#define RETURN(x) {res = x; goto CLEARRETURN;}
char logident[128];
int readconfig(FILE * fp){
unsigned char ** args = NULL;
unsigned char * buf = NULL;
pthread_t thread;
struct child chdata;
struct child * ch=&chdata;
int bufsize = STRINGBUF*2;
int inbuf = 0;
int cargc;
struct ace *acl = NULL;
struct passwords *pwl = NULL;
struct chain *chains;
unsigned char *arg;
int res = 0;
#ifdef _WIN32
HANDLE h;
#endif
if( !(buf = myalloc(bufsize)) || ! (args = myalloc(NPARAMS * sizeof(unsigned char *) + 1)) ) {
fprintf(stderr, "No memory for configuration");
return(10);
}
ch->argv = args;
for (linenum = 1; fgets((char *)buf, STRINGBUF, fp); linenum++){
if(!*buf || isspace(*buf) || (*buf) == '#')continue;
inbuf = (strlen((char *)buf) + 1);
cargc = parsestr (buf, args, NPARAMS-1, buf, &inbuf, &bufsize);
if(cargc < 1) {
fprintf(stderr, "Parse error line %d\n", linenum);
return(21);
}
ch->argv[cargc] = NULL;
ch->argc = cargc;
if(!strcmp((char *)ch->argv[0], "proxy")) {
childdef.pf = proxychild;
childdef.port = 3128;
childdef.isudp = 0;
childdef.service = S_PROXY;
childdef.helpmessage = " -n - no NTLM support\n";
}
else if(!strcmp((char *)ch->argv[0], "pop3p")) {
childdef.pf = pop3pchild;
childdef.port = 110;
childdef.isudp = 0;
childdef.service = S_POP3P;
childdef.helpmessage = "";
}
else if(!strcmp((char *)ch->argv[0], "ftppr")) {
childdef.pf = ftpprchild;
childdef.port = 21;
childdef.isudp = 0;
childdef.service = S_FTPPR;
childdef.helpmessage = "";
}
else if(!strcmp((char *)ch->argv[0], "socks")) {
childdef.pf = sockschild;
childdef.port = 1080;
childdef.isudp = 0;
childdef.service = S_SOCKS;
childdef.helpmessage = " -n - no NTLM support\n";
}
else if(!strcmp((char *)ch->argv[0], "tcppm")) {
childdef.pf = tcppmchild;
childdef.port = 0;
childdef.isudp = 0;
childdef.service = S_TCPPM;
childdef.helpmessage = "";
}
else if(!strcmp((char *)ch->argv[0], "udppm")) {
childdef.pf = udppmchild;
childdef.port = 0;
childdef.isudp = 1;
childdef.service = S_UDPPM;
childdef.helpmessage = " -s single packet UDP service for request/reply (DNS-like) services\n";
}
else if(!strcmp((char *)ch->argv[0], "admin")) {
childdef.pf = adminchild;
childdef.port = 80;
childdef.isudp = 0;
childdef.service = S_ADMIN;
}
else if(!strcmp((char *)ch->argv[0], "dnspr")) {
childdef.pf = dnsprchild;
childdef.port = 53;
childdef.isudp = 1;
childdef.service = S_DNSPR;
}
else if(!strcmp((char *)ch->argv[0], "internal") && ch->argc == 2) {
conf.intip = getip((unsigned char *)ch->argv[1]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "external") && ch->argc == 2) {
conf.extip = getip((unsigned char *)ch->argv[1]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "log") && ch->argc <= 3) {
conf.logfunc = logstdout;
if(ch->argc > 1) {
if(*ch->argv[1]=='@'){
#ifndef _WIN32
res = (int) strlen((char *)ch->argv[1]+1);
if(res>127) res = 127;
memcpy(logident, ch->argv[1]+1, res+1);
logident[127] = 0;
openlog(logident, LOG_PID, LOG_DAEMON);
conf.logfunc = logsyslog;
#endif
}
#ifndef NOODBC
else if(*ch->argv[1]=='&'){
pthread_mutex_lock(&odbc_mutex);
close_sql();
init_sql((char *)ch->argv[1]+1);
pthread_mutex_unlock(&odbc_mutex);
conf.logfunc = logsql;
}
#endif
else {
FILE *fp, *fp1;
if(ch->argc > 2) {
switch(*ch->argv[2]){
case 'd':
case 'D':
conf.logtype = DAILY;
break;
case 'w':
case 'W':
conf.logtype = WEEKLY;
break;
case 'y':
case 'Y':
conf.logtype = ANNUALLY;
break;
case 'm':
case 'M':
conf.logtype = MONTHLY;
break;
case 'h':
case 'H':
conf.logtype = HOURLY;
break;
case 'c':
case 'C':
conf.logtype = MINUTELY;
break;
default:
break;
}
}
logtime = time(0);
conf.logname = (unsigned char *)mystrdup((char *)ch->argv[1]);
fp = fopen((char *)dologname (tmpbuf, conf.logname, NULL, conf.logtype, logtime), "a");
if(!fp){
perror("fopen()");
}
else {
fp1 = stdlog;
stdlog = fp;
if(fp1) fclose(fp1);
}
}
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "service") && ch->argc == 1) {
#ifdef _WIN32
if(osv.dwPlatformId == VER_PLATFORM_WIN32_NT) service = 1;
else {
if(!demon)daemonize();
demon = 1;
}
#endif
continue;
}
else if(!strcmp((char *)ch->argv[0], "daemon") && ch->argc == 1) {
if(!demon)daemonize();
demon = 1;
continue;
}
else if(!strcmp((char *)ch->argv[0], "writable") && ch->argc == 1) {
if(!writable){
writable = freopen(curconf, "r+", fp);
if(!writable){
fprintf(stderr, "Unable to reopen config for writing: %s\n", curconf);
return -28;
}
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "end") && ch->argc == 1) {
break;
}
else if(!strcmp((char *)ch->argv[0], "config") && ch->argc == 2) {
if(conffile)myfree(conffile);
conffile = mystrdup((char *)ch->argv[1]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "include") && ch->argc == 2) {
FILE *fp1;
fp1 = fopen((char *)ch->argv[1], "r");
if(!fp1){
fprintf(stderr, "Unable to open included file: %s\n", ch->argv[1]);
return -28;
}
res = readconfig(fp1);
fclose(fp1);
if(res) return res;
continue;
}
else if(!strcmp((char *)ch->argv[0], "archiver") && ch->argc > 2) {
int j;
conf.archiver = myalloc(ch->argc * sizeof(char *));
if(conf.archiver) {
conf.archiverc = ch->argc;
for(j = 0; j < conf.archiverc; j++) conf.archiver[j] = (unsigned char *)mystrdup((char *)ch->argv[j]);
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "counter") && ch->argc >= 2) {
if(conf.counterd >=0)close(conf.counterd);
conf.counterd = open((char *)ch->argv[1], O_BINARY|O_RDWR|O_CREAT, 0660);
if(conf.counterd<0){
fprintf(stderr, "Unable to open counter file %s, line %d\n", ch->argv[1], linenum);
return(18);
}
if(ch->argc >=4) {
switch(*ch->argv[2]){
case 'd':
case 'D':
conf.countertype = DAILY;
break;
case 'w':
case 'W':
conf.countertype = WEEKLY;
break;
case 'y':
case 'Y':
conf.countertype = ANNUALLY;
break;
case 'm':
case 'M':
conf.countertype = MONTHLY;
break;
case 'h':
case 'H':
conf.countertype = HOURLY;
break;
case 'c':
case 'C':
conf.countertype = MINUTELY;
break;
default:
fprintf(stderr, "Unknown counter type, line: %d\n", linenum);
return(18);
}
conf.counterfile = mystrdup((char *)ch->argv[3]);
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "rotate") && ch->argc == 2) {
conf.rotate = atoi((char *)ch->argv[1]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "logformat") && ch->argc == 2 && strlen((char *)ch->argv[1])) {
if(conf.logformat) myfree(conf.logformat);
conf.logformat = (unsigned char *)mystrdup((char *)ch->argv[1]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "timeouts") && ch->argc > 1) {
int j;
for(j = 0; conf.timeouts[j] && j + 1 < ch->argc; j++) {
if((conf.timeouts[j] = atoi((char *)ch->argv[j + 1])) <= 0 || conf.timeouts[j] > 2000000){
fprintf(stderr, "Invalid timeout: %s, line %d\n", ch->argv[j + 1], linenum);
return(19);
}
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "auth") && ch->argc == 2) {
if(!strcmp((char *)ch->argv[1], "none")){
conf.authfunc = alwaysauth;
}
else if (!strcmp((char *)ch->argv[1], "iponly")){
conf.authfunc = ipauth;
}
else if (!strcmp((char *)ch->argv[1], "nbname")){
conf.authfunc = nbnameauth;
}
else if (!strcmp((char *)ch->argv[1], "strong")){
conf.authfunc = strongauth;
}
else {
fprintf(stderr, "Unknown auth type: '%s' line %d\n", ch->argv[1], linenum);
return(22);
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "maxconn") && ch->argc == 2) {
conf.maxchild = atoi((char *)ch->argv[1]);
if(!conf.maxchild) {
fprintf(stderr, "Invalid maxconn value, line %d\n", linenum);
return(22);
}
continue;
}
else if (!strcmp((char *)ch->argv[0], "users") && ch->argc >= 2) {
int j;
for (j = 1; j<ch->argc; j++) {
if(!conf.pwl)conf.pwl = pwl = myalloc(sizeof(struct passwords));
else {
pwl->next = myalloc(sizeof(struct passwords));
pwl = pwl->next;
}
if(!pwl) {
fprintf(stderr, "No memory for PWL entry, line %d\n", linenum);
return(22);
}
memset(pwl, 0, sizeof(struct passwords));
pwl->user = (unsigned char *)mystrdup((char *)ch->argv[j]);
arg = (unsigned char *)strchr((char *)pwl->user, ':');
if(!arg||!arg[1]||!arg[2]||arg[3]!=':') {
continue;
}
pwl->password = arg + 4;
if(arg[1] == 'C' && arg[2] == 'L')pwl->pwtype = CL;
else if(arg[1] == 'C' && arg[2] == 'R')pwl->pwtype = CR;
else if(arg[1] == 'N' && arg[2] == 'T'){
pwl->pwtype = NT;
fromhex(pwl->password, pwl->password, (strlen((char *)pwl->password)>>1));
}
else if(arg[1] == 'L' && arg[2] == 'M')pwl->pwtype = LM;
else {
continue;
}
*arg = 0;
}
continue;
}
else if (( (!strcmp((char *)ch->argv[0], "allow") && (res=ALLOW) == ALLOW) ||
(!strcmp((char *)ch->argv[0], "deny") && (res=DENY) == DENY) ||
(!strcmp((char *)ch->argv[0], "redirect") && ch->argc >= 3 && (res=REDIRECT) ==REDIRECT) ||
(!strcmp((char *)ch->argv[0], "bandlimin") && ch->argc >= 2 && (res=BANDLIM) ==BANDLIM) ||
(!strcmp((char *)ch->argv[0], "bandlimout") && ch->argc >= 2 && (res=BANDLIM) ==BANDLIM) ||
(!strcmp((char *)ch->argv[0], "nobandlimin") && (res=NOBANDLIM) ==NOBANDLIM) ||
(!strcmp((char *)ch->argv[0], "nobandlimout") && (res=NOBANDLIM) ==NOBANDLIM) ||
(!strcmp((char *)ch->argv[0], "countin") && ch->argc >= 4 && (res=COUNT) ==COUNT) ||
(!strcmp((char *)ch->argv[0], "nocountin") && (res=NOCOUNT) ==NOCOUNT)
)) {
int offset = 0;
struct iplist *ipl=NULL;
struct portlist *portl=NULL;
struct userlist *userl=NULL;
if(res == REDIRECT) offset = 2;
else if(res == BANDLIM) offset = 1;
else if(res == COUNT) offset = 3;
acl = myalloc(sizeof(struct ace));
if(!acl) {
fprintf(stderr, "No memory for ACL entry, line %d\n", linenum);
return(22);
}
memset(acl, 0, sizeof(struct ace));
acl->action = res;
if(res == 2){
acl->chains = myalloc(sizeof(struct chain));
if(!acl->chains) {
fprintf(stderr, "No memory for ACL entry, line %d\n", linenum);
return(22);
}
acl->chains->type = R_HTTP;
acl->chains->redirip = getip(ch->argv[1]);
acl->chains->redirport = htons((unsigned short)atoi((char *)ch->argv[2]));
acl->chains->weight = 1000;
acl->chains->extuser = NULL;
acl->chains->extpass = NULL;
acl->chains->next = NULL;
}
if(ch->argc - offset >= 2 && strcmp("*", (char *)ch->argv[1 + offset])) {
arg = (unsigned char *)mystrdup((char *)ch->argv[1 + offset]);
arg = (unsigned char *)strtok((char *)arg, ",");
do {
if(!acl->users) {
acl->users = userl = myalloc(sizeof(struct userlist));
}
else {
userl->next = myalloc(sizeof(struct userlist));
userl = userl -> next;
}
if(!userl) {
fprintf(stderr, "No memory for ACL entry, line %d\n", linenum);
return(22);
}
memset(userl, 0, sizeof(struct userlist));
userl->user=arg;
} while((arg = (unsigned char *)strtok((char *)NULL, ",")));
}
if(ch->argc - offset >= 3 && strcmp("*", (char *)ch->argv[2 + offset])) {
arg = (unsigned char *)strtok((char *)ch->argv[2 + offset], ",");
do {
if(!acl->src) {
acl->src = ipl = myalloc(sizeof(struct iplist));
}
else {
ipl->next = myalloc(sizeof(struct iplist));
ipl = ipl -> next;
}
if(!ipl) {
fprintf(stderr, "No memory for ACL entry, line %d\n", linenum);
return(22);
}
memset(ipl, 0, sizeof(struct iplist));
if (!scanaddr(arg, &ipl->ip, &ipl->mask)) {
fprintf(stderr, "Invalid IP or CIDR, line %d\n", linenum);
return(22);
}
} while((arg = (unsigned char *)strtok((char *)NULL, ",")));
}
if(ch->argc - offset >= 4 && strcmp("*", (char *)ch->argv[3 + offset])) {
arg = (unsigned char *)strtok((char *)ch->argv[3 + offset], ",");
do {
if(!acl->dst) {
acl->dst = ipl = myalloc(sizeof(struct iplist));
}
else {
ipl->next = myalloc(sizeof(struct iplist));
ipl = ipl -> next;
}
if(!ipl) {
fprintf(stderr, "No memory for ACL entry, line %d\n", linenum);
return(22);
}
memset(ipl, 0, sizeof(struct iplist));
if (!scanaddr(arg, &ipl->ip, &ipl->mask)) {
fprintf(stderr, "Invalid IP or CIDR, line %d\n", linenum);
return(22);
}
} while((arg = (unsigned char *)strtok((char *)NULL, ",")));
}
if(ch->argc - offset >= 5 && strcmp("*", (char *)ch->argv[4 + offset])) {
arg = (unsigned char *)strtok((char *)ch->argv[4 + offset], ",");
do {
if(!acl->ports) {
acl->ports = portl = myalloc(sizeof(struct portlist));
}
else {
portl->next = myalloc(sizeof(struct portlist));
portl = portl -> next;
}
if(!portl) {
fprintf(stderr, "No memory for ACL entry, line %d\n", linenum);
return(22);
}
memset(portl, 0, sizeof(struct portlist));
res = sscanf((char *)arg, "%hu-%hu", &portl->startport, &portl->endport);
if(res < 1) {
fprintf(stderr, "Invalid port or port range, line %d\n", linenum);
return(23);
}
if (res == 1) portl->endport = portl->startport;
} while((arg = (unsigned char *)strtok((char *)NULL, ",")));
}
if(ch->argc - offset >= 6 && strcmp("*", (char *)ch->argv[5 + offset])) {
arg = (unsigned char *)strtok((char *)ch->argv[5 + offset], ",");
do {
if(!strcmp((char *)arg, "CONNECT")){
acl->operation |= CONNECT;
}
else if(!strcmp((char *)arg, "BIND")){
acl->operation |= BIND;
}
else if(!strcmp((char *)arg, "UDPASSOC")){
acl->operation |= UDPASSOC;
}
else if(!strcmp((char *)arg, "ICMPASSOC")){
acl->operation |= ICMPASSOC;
}
else if(!strcmp((char *)arg, "HTTP_GET")){
acl->operation |= HTTP_GET;
}
else if(!strcmp((char *)arg, "HTTP_PUT")){
acl->operation |= HTTP_PUT;
}
else if(!strcmp((char *)arg, "HTTP_POST")){
acl->operation |= HTTP_POST;
}
else if(!strcmp((char *)arg, "HTTP_HEAD")){
acl->operation |= HTTP_HEAD;
}
else if(!strcmp((char *)arg, "HTTP_OTHER")){
acl->operation |= HTTP_OTHER;
}
else if(!strcmp((char *)arg, "HTTP_CONNECT")){
acl->operation |= HTTP_CONNECT;
}
else if(!strcmp((char *)arg, "HTTP")){
acl->operation |= HTTP;
}
else if(!strcmp((char *)arg, "HTTPS")){
acl->operation |= HTTPS;
}
else if(!strcmp((char *)arg, "FTP_GET")){
acl->operation |= FTP_GET;
}
else if(!strcmp((char *)arg, "FTP_PUT")){
acl->operation |= FTP_PUT;
}
else if(!strcmp((char *)arg, "FTP_LIST")){
acl->operation |= FTP_LIST;
}
else if(!strcmp((char *)arg, "FTP")){
acl->operation |= FTP;
}
else if(!strcmp((char *)arg, "ADMIN")){
acl->operation |= ADMIN;
}
else {
fprintf(stderr, "Unknown operation type: %s line %d\n", arg, linenum);
return(31);
}
} while((arg = (unsigned char *)strtok((char *)NULL, ",")));
}
if(ch->argc - offset >= 7){
for(arg = ch->argv[6 + offset]; *arg;){
int val, val1;
if(!isnumber(*arg)) {
arg++;
continue;
}
val1 = val = (*arg - '0');
arg++;
if(*arg == '-' && isnumber(*(arg+1)) && (*(arg+1) - '0') > val) {
val1 = (*(arg+1) - '0');
arg+=2;
}
for(; val<=val1; val++) acl->wdays |= (1 << (val % 7));
}
}
if(ch->argc - offset >= 8){
for(arg = ch->argv[7 + offset]; strlen((char *)arg) >= 17 &&
isdigit(arg[0]) &&
isdigit(arg[1]) &&
isdigit(arg[3]) &&
isdigit(arg[4]) &&
isdigit(arg[6]) &&
isdigit(arg[7]) &&
isdigit(arg[9]) &&
isdigit(arg[10]) &&
isdigit(arg[12]) &&
isdigit(arg[13]) &&
isdigit(arg[15]) &&
isdigit(arg[16])
; arg+=18){
int t1, t2;
struct period *sp;
t1 = (arg[0] - '0') * 10 + (arg[1] - '0');
t1 = (t1 * 60) + (arg[3] - '0') * 10 + (arg[4] - '0');
t1 = (t1 * 60) + (arg[6] - '0') * 10 + (arg[7] - '0');
t2 = (arg[9] - '0') * 10 + (arg[10] - '0');
t2 = (t2 * 60) + (arg[12] - '0') * 10 + (arg[13] - '0');
t2 = (t2 * 60) + (arg[15] - '0') * 10 + (arg[16] - '0');
if(t2 < t1) break;
sp = myalloc(sizeof(struct period));
if(sp){
sp->fromtime = t1;
sp->totime = t2;
sp->next = acl->periods;
acl->periods = sp;
}
if(arg[17]!=',') break;
}
}
if(acl->action == ALLOW || acl->action == DENY || acl->action == REDIRECT) {
pthread_mutex_lock(&acl_mutex);
if(!conf.acls[conf.aclnum]){
conf.acls[conf.aclnum] = acl;
}
else {
struct ace * acei;
for(acei = conf.acls[conf.aclnum]; acei->next; acei = acei->next);
acei->next = acl;
}
pthread_mutex_unlock(&acl_mutex);
}
else if (acl->action == BANDLIM || acl->action == NOBANDLIM) {
struct bandlim * nbl;
nbl = myalloc(sizeof(struct bandlim));
if(!nbl) {
fprintf(stderr, "No memory to create band limit filter\n");
return(32);
}
memset(nbl, 0, sizeof(struct bandlim));
nbl->ace = acl;
if(acl->action == BANDLIM) {
sscanf((char *)ch->argv[1], "%u", &nbl->rate);
if(nbl->rate < 300) {
fprintf(stderr, "Wrong bandwidth specified, line %d\n", linenum);
return(33);
}
}
pthread_mutex_lock(&bandlim_mutex);
if(!strcmp((char *)ch->argv[0], "bandlimin") || !strcmp((char *)ch->argv[0], "nobandlimin")){
if(!conf.bandlimiter){
conf.bandlimiter = nbl;
}
else {
struct bandlim * bli;
for(bli = conf.bandlimiter; bli->next; bli = bli->next);
bli->next = nbl;
}
}
else {
if(!conf.bandlimiterout){
conf.bandlimiterout = nbl;
}
else {
struct bandlim * bli;
for(bli = conf.bandlimiterout; bli->next; bli = bli->next);
bli->next = nbl;
}
}
pthread_mutex_unlock(&bandlim_mutex);
}
else if (acl->action == COUNT || acl->action == NOCOUNT) {
struct trafcount * tl;
tl = myalloc(sizeof(struct trafcount));
if(!tl) {
fprintf(stderr, "No memory to create traffic limit filter\n");
return(32);
}
memset(tl, 0, sizeof(struct trafcount));
tl->ace = acl;
if(acl->action == COUNT) {
unsigned long lim;
tl->comment = mystrdup((char *)ch->argv[1]);
while(isdigit(*tl->comment))tl->comment++;
if(*tl->comment== '/')tl->comment++;
sscanf((char *)ch->argv[1], "%u", &tl->number);
sscanf((char *)ch->argv[3], "%lu", &lim);
tl->traflimgb = (lim/1024);
tl->traflim = ((lim % 1024)*(1024*1024));
switch(*ch->argv[2]){
case 'c':
case 'C':
tl->type = DAILY;
break;
case 'h':
case 'H':
tl->type = DAILY;
break;
case 'd':
case 'D':
tl->type = DAILY;
break;
case 'w':
case 'W':
tl->type = WEEKLY;
break;
case 'y':
case 'Y':
tl->type = ANNUALLY;
break;
case 'm':
case 'M':
tl->type = MONTHLY;
break;
case 'n':
case 'N':
tl->type = NEVER;
break;
default:
fprintf(stderr, "Unknown rotation type, line: %d\n", linenum);
return(34);
}
if(!tl->traflim && !tl->traflimgb) {
fprintf(stderr, "Wrong traffic limit specified, line %d\n", linenum);
return(35);
}
if(tl->number != 0 && conf.counterd >= 0) {
lseek(conf.counterd,
sizeof(struct counter_header) + (tl->number - 1) * sizeof(struct counter_record),
SEEK_SET);
memset(&crecord, 0, sizeof(struct counter_record));
read(conf.counterd, &crecord, sizeof(struct counter_record));
tl->traf = crecord.traf;
tl->trafgb = crecord.trafgb;
tl->cleared = crecord.cleared;
tl->updated = crecord.updated;
}
}
pthread_mutex_lock(&tc_mutex);
if(!conf.trafcounter){
conf.trafcounter = tl;
}
else {
struct trafcount * ntl;
for(ntl = conf.trafcounter; ntl->next; ntl = ntl->next);
ntl->next = tl;
}
pthread_mutex_unlock(&tc_mutex);
/*
tl->next = conf.trafcounter;
conf.trafcounter = tl;
*/
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "flush") && ch->argc == 1) {
if (conf.aclnum<255) conf.aclnum++;
continue;
}
else if(!strcmp((char *)ch->argv[0], "parent") && ch->argc >=5) {
if(!acl || (acl->action && acl->action != 2)) {
fprintf(stderr, "Chaining error: last ACL entry was not \"allow\" or \"redirect\" on line %d\n", linenum);
return(41);
}
acl->action = 2;
chains = NULL;
if(!acl->chains) {
chains = acl->chains = myalloc(sizeof(struct chain));
}
else {
chains = acl->chains;
while(chains->next)chains = chains->next;
chains->next = myalloc(sizeof(struct chain));
chains = chains->next;
}
memset(chains, 0, sizeof(struct chain));
if(!chains){
fprintf(stderr, "Chainig error: unable to allocate memory for chain\n");
return(44);
}
chains->weight = (unsigned)atoi((char *)ch->argv[1]);
if(chains->weight == 0 || chains->weight >1000) {
fprintf(stderr, "Chaining error: bad chain weight %u line %d\n", chains->weight, linenum);
return(42);
}
if(!strcmp((char *)ch->argv[2], "tcp"))chains->type = R_TCP;
else if(!strcmp((char *)ch->argv[2], "http"))chains->type = R_HTTP;
else if(!strcmp((char *)ch->argv[2], "connect"))chains->type = R_CONNECT;
else if(!strcmp((char *)ch->argv[2], "socks4"))chains->type = R_SOCKS4;
else if(!strcmp((char *)ch->argv[2], "socks5"))chains->type = R_SOCKS5;
else if(!strcmp((char *)ch->argv[2], "connect+"))chains->type = R_CONNECTP;
else if(!strcmp((char *)ch->argv[2], "socks4+"))chains->type = R_SOCKS4P;
else if(!strcmp((char *)ch->argv[2], "socks5+"))chains->type = R_SOCKS5P;
else if(!strcmp((char *)ch->argv[2], "socks4b"))chains->type = R_SOCKS4B;
else if(!strcmp((char *)ch->argv[2], "socks5b"))chains->type = R_SOCKS5B;
else if(!strcmp((char *)ch->argv[2], "pop3"))chains->type = R_POP3;
else if(!strcmp((char *)ch->argv[2], "ftp"))chains->type = R_FTP;
else {
fprintf(stderr, "Chaining error: bad chain type (%s)\n", ch->argv[2]);
return(43);
}
chains->redirip = getip(ch->argv[3]);
chains->redirport = htons((unsigned short)atoi((char *)ch->argv[4]));
if(ch->argc > 5) chains->extuser = (unsigned char *)mystrdup((char *)ch->argv[5]);
if(ch->argc > 6) chains->extpass = (unsigned char *)mystrdup((char *)ch->argv[6]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "nserver") && ch->argc == 2) {
for(res = 0; nservers[res] && res < MAXNSERVERS; res++);
if(res < MAXNSERVERS) {
nservers[res] = getip(ch->argv[1]);
}
resolvfunc = myresolver;
continue;
}
else if(!strcmp((char *)ch->argv[0], "fakeresolve") && ch->argc == 1) {
resolvfunc = fakeresolver;
continue;
}
else if(!strcmp((char *)ch->argv[0], "nscache") && ch->argc == 2) {
res = atoi((char *)ch->argv[1]);
if(res < 256) {
fprintf(stderr, "Invalid NS cache size: %d\n", res);
}
if(inithashtable((unsigned)res)){
fprintf(stderr, "Failed to initialize NS cache\n");
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "nsrecord") && ch->argc == 3) {
hashadd((unsigned char *)mystrdup((char *)ch->argv[1]), getip(ch->argv[2]), (time_t)0xffffffff);
continue;
}
else if(!strcmp((char *)ch->argv[0], "dialer") && ch->argc == 2) {
demanddialprog = mystrdup((char *)ch->argv[1]);
continue;
}
else if(!strcmp((char *)ch->argv[0], "monitor") && ch->argc == 2) {
struct filemon * fm;
fm = myalloc(sizeof (struct filemon));
if(stat(ch->argv[1], &fm->sb)){
myfree(fm);
fprintf(stderr, "Warning: file %s doesn't exist on line %d\n", ch->argv[1], linenum);
}
else {
fm->path = mystrdup(ch->argv[1]);
fm->next = conf.fmon;
conf.fmon = fm;
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "system") && ch->argc == 2) {
if((res = system((char *)ch->argv[1])) == -1){
fprintf(stderr, "Failed to start %s\n", ch->argv[1]);
return(33);
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "pidfile") && ch->argc == 2) {
FILE *pidf;
if(!(pidf = fopen((char *)ch->argv[1], "w"))){
fprintf(stderr, "Failed to open pid file %s\n", ch->argv[1]);
return(34);
}
fprintf(pidf,"%u", (unsigned)getpid());
fclose(pidf);
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);
}
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);
}
continue;
}
else if(!strcmp((char *)ch->argv[0], "chroot") && ch->argc == 2) {
if(!chrootp){
char *p;
if(chroot((char *)ch->argv[1])) {
fprintf(stderr, "Unable to chroot %s", ch->argv[1]);
return(32);
}
p = (char *)ch->argv[1] + strlen((char *)ch->argv[1]) ;
while (p > (char *)ch->argv[1] && p[-1] == '/'){
p--;
*p = 0;
}
chrootp = strdup((char *)ch->argv[1]);
}
continue;
}
#endif
else {
fprintf(stderr, "Unknown command: '%s' line %d\n", ch->argv[0], linenum);
return(22);
}
conf.threadinit = 1;
#ifdef _WIN32
h = CreateThread((LPSECURITY_ATTRIBUTES )NULL, 0, startsrv, (void *) ch, (DWORD)0, &thread);
if(h)CloseHandle(h);
#else
pthread_attr_init(&pa);
pthread_attr_setstacksize(&pa,PTHREAD_STACK_MIN + 16384);
pthread_attr_setdetachstate(&pa,PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &pa, startsrv, (void *)ch);
#endif
while(conf.threadinit)usleep(SLEEPTIME);
if(haveerror) {
fprintf(stderr, "Service not started on line: %d\n", linenum);
return(40);
}
}
myfree(buf);
buf = NULL;
myfree(args);
args = NULL;
return 0;
}
int main(int argc, char * argv[]) {
int res = 0;
FILE * fp = NULL;
#ifdef _WIN32
unsigned char * arg;
WSADATA wd;
WSAStartup(MAKEWORD( 1, 1 ), &wd);
osv.dwOSVersionInfoSize = sizeof(osv);
GetVersionEx(&osv);
#endif
stringtable = strings;
#ifdef _WIN32
if((argc == 2 || argc == 3)&& !strcmp((char *)argv[1], "--install")) {
sprintf((char *)tmpbuf, "%s will be installed and started.\n"
"By clicking Yes you confirm you read and accepted License Agreement.\n"
"You can use Administration/Services to control %s service.",
stringtable[1], stringtable[2]);
if(MessageBox(NULL, (char *)tmpbuf, stringtable[2], MB_YESNO|MB_ICONASTERISK) != IDYES) return 1;
*tmpbuf = '\"';
if (!(res = SearchPath(NULL, argv[0], ".exe", 256, (char *)tmpbuf+1, (char **)&arg))) {
perror("Failed to find executable filename");
RETURN(102);
}
strcat((char *)tmpbuf, "\" \"");
if(!(res = GetFullPathName ((argc == 3)?argv[2]:(char*)DEFAULTCONFIG, 256, (char *)tmpbuf+res+4, (char **)&arg))){
perror("Failed to find config filename");
RETURN(103);
}
strcat((char *)tmpbuf, "\"");
if(osv.dwPlatformId == VER_PLATFORM_WIN32_NT){
SC_HANDLE sch;
if(!(sch = OpenSCManager(NULL, NULL, GENERIC_WRITE|SERVICE_START ))){
perror("Failed to open Service Manager");
RETURN(101);
}
if (!(sch = CreateService(sch, stringtable[1], stringtable[2], GENERIC_EXECUTE, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, (char *)tmpbuf, NULL, NULL, NULL, NULL, NULL))){
perror("Failed to create service");
RETURN(103);
}
if (!StartService(sch, 0, NULL)) {
perror("Failed to start service");
RETURN(103);
}
}
else {
HKEY runsrv;
if(RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
0,
KEY_ALL_ACCESS,
&runsrv) != ERROR_SUCCESS){
perror("Failed to open registry");
RETURN(104);
}
if(RegSetValueEx( runsrv,
stringtable[1],
0,
REG_EXPAND_SZ,
(char *)tmpbuf,
strlen((char *)tmpbuf)+1)!=ERROR_SUCCESS){
perror("Failed to set registry value");
RETURN(105);
}
}
return 0;
}
if((argc == 2 || argc == 3)&& !strcmp((char *)argv[1], "--remove")) {
if(osv.dwPlatformId == VER_PLATFORM_WIN32_NT){
SC_HANDLE sch;
if(!(sch = OpenSCManager(NULL, NULL, GENERIC_WRITE))){
perror("Failed to open Service Manager\n");
RETURN(106);
}
if (!(sch = OpenService(sch, stringtable[1], DELETE))){
perror("Failed to open service");
RETURN(107);
}
if (!DeleteService(sch)){
perror("Failed to delete service");
RETURN(108);
}
}
else {
HKEY runsrv;
if(RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
0,
KEY_ALL_ACCESS,
&runsrv) != ERROR_SUCCESS){
perror("Failed to open registry");
RETURN(109);
}
if(RegDeleteValue(runsrv, stringtable[1]) != ERROR_SUCCESS){
perror("Failed to clear registry");
RETURN(110);
}
}
RETURN(0);
}
#endif
conffile = mystrdup((argc==2)?argv[1]:(char*)DEFAULTCONFIG);
if(conffile && *conffile != '-') {
fp = confopen();
#ifndef _WIN32
if(!fp) fp = stdin;
#endif
}
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;
}
pthread_mutex_init(&acl_mutex, NULL);
pthread_mutex_init(&bandlim_mutex, NULL);
pthread_mutex_init(&hash_mutex, NULL);
pthread_mutex_init(&tc_mutex, NULL);
#ifndef NOODBC
pthread_mutex_init(&odbc_mutex, NULL);
#endif
res = readconfig(fp);
if(res) RETURN(res);
if(!writable)fclose(fp);
#ifdef _WIN32
if(service){
SERVICE_TABLE_ENTRY ste[] =
{
{ stringtable[1], (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{ NULL, NULL }
};
if(!StartServiceCtrlDispatcher( ste ))cyclestep();
}
else {
cyclestep();
}
#else
signal(SIGCONT, mysigpause);
signal(SIGTERM, mysigterm);
signal(SIGUSR1, mysigusr1);
signal(SIGPIPE, SIG_IGN);
cyclestep();
#endif
CLEARRETURN:
/*
if(1) {
char t[256];
sprintf(t, "echo result:%d lines: %d>c:\\result.txt", res, linenum);
system(t);
}
*/
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1