void * pop3pchild(void * data) { #define param ((struct clientparam*)data) int i=0, res; unsigned char buf[320]; unsigned char *se; if(socksend(param->clisock, (unsigned char *)"+OK Proxy\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (611);} i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); while(i > 4 && strncasecmp((char *)buf, "USER", 4)){ if(!strncasecmp((char *)buf, "QUIT", 4)){ socksend(param->clisock, (unsigned char *)"+OK\r\n", 5,conf.timeouts[STRING_S]); RETURN(0); } socksend(param->clisock, (unsigned char *)"-ERR need USER first\r\n", 22, conf.timeouts[STRING_S]); i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); } if(i<6) {RETURN(612);} buf[i] = 0; if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0; if (strncasecmp((char *)buf, "USER ", 5)){RETURN (614);} if(!param->hostname && param->remsock == INVALID_SOCKET) { if(parseconnusername((char *)buf +5, param, 0, 110)){RETURN(615);} } else if(parseusername((char *)buf + 5, param, 0)) {RETURN(616);} param->operation = CONNECT; res = (*param->authfunc)(param); if(res) {RETURN(res);} i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]); param->statssrv+=i; if( i < 3 ) {RETURN(621);} buf[i] = 0; if(strncasecmp((char *)buf, "+OK", 3)||!strncasecmp((char *)buf+4, "PROXY", 5)){RETURN(622);} if( socksend(param->remsock, (unsigned char *)"USER ", 5, conf.timeouts[STRING_S])!= 5 || socksend(param->remsock, param->extusername, strlen((char *)param->extusername), conf.timeouts[STRING_S]) <= 0 || socksend(param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S])!=2) {RETURN(623);} param->statscli += (strlen((char *)param->extusername) + 7); RETURN (sockmap(param, 180)); CLEANRET: if(param->hostname&¶m->extusername) { sprintf((char *)buf, "%.64s@%.128s%c%hu", param->extusername, param->hostname, (ntohs(param->sins.sin_port)==110)?0:':', ntohs(param->sins.sin_port)); (*param->logfunc)(param, buf); } else (*param->logfunc)(param, NULL); if(param->clisock != INVALID_SOCKET) { if ((param->res > 0 && param->res < 100) || (param->res > 611 && param->res <700)) socksend(param->clisock, (unsigned char *)"-ERR\r\n", 6,conf.timeouts[STRING_S]); } freeparam(param); return (NULL); }
void * ftpprchild(struct clientparam* param) { int i=0, res; unsigned char *buf; unsigned char *se; int status = 0; int inbuf; int pasv = 0; SOCKET sc = INVALID_SOCKET, ss = INVALID_SOCKET, clidatasock = INVALID_SOCKET; SASIZETYPE sasize; char * req = NULL; struct linger lg; struct pollfd fds; if(!(buf = myalloc(BUFSIZE))) RETURN(876); param->ctrlsock = param->clisock; param->operation = CONNECT; lg.l_onoff = 1; lg.l_linger = conf.timeouts[STRING_L];; if(socksend(param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);} for(;;){ i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 10, '\n', conf.timeouts[CONNECTION_S]); if(!i) { RETURN(0); } if(i<4) {RETURN(802);} buf[i] = 0; if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0; if (req) myfree (req); req = NULL; if (!strncasecmp((char *)buf, "OPEN ", 5)){ if(parsehostname((char *)buf+5, param, 21)){RETURN(803);} if(param->remsock != INVALID_SOCKET) { so._shutdown(param->remsock, SHUT_RDWR); so._closesocket(param->remsock); param->remsock = INVALID_SOCKET; } if((res = (*param->srv->authfunc)(param))) {RETURN(res);} param->ctrlsocksrv = param->remsock; if(socksend(param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);} status = 1; } else if (!strncasecmp((char *)buf, "USER ", 5)){ if(parseconnusername((char *)buf +5, param, 0, 21)){RETURN(804);} if(!status){ if((res = (*param->srv->authfunc)(param))) {RETURN(res);} param->ctrlsocksrv = param->remsock; } if(socksend(param->ctrlsock, (unsigned char *)"331 ok\r\n", 8, conf.timeouts[STRING_S])!=8) {RETURN (807);} status = 2; } else if (!strncasecmp((char *)buf, "PASS ", 5)){ param->extpassword = (unsigned char *)mystrdup((char *)buf+5); inbuf = BUFSIZE; res = ftplogin(param, (char *)buf, &inbuf); param->res = res; if(inbuf && inbuf != BUFSIZE && socksend(param->ctrlsock, buf, inbuf, conf.timeouts[STRING_S])!=inbuf) {RETURN (807);} if(!res) status = 3; sprintf((char *)buf, "%.64s@%.128s%c%hu", param->extusername, param->hostname, (ntohs(param->sins.sin_port)==21)?0:':', ntohs(param->sins.sin_port)); req = mystrdup((char *)buf); #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlereqfilters(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(877); } #endif } else if (status >= 3 && ( (!strncasecmp((char *)buf, "PASV", 4) && (pasv = 1)) || (!strncasecmp((char *)buf, "PORT ", 5) && !(pasv = 0)) )){ #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlehdrfilterscli(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(878); } #endif if(sc != INVALID_SOCKET) { so._shutdown(sc, SHUT_RDWR); so._closesocket(sc); sc = INVALID_SOCKET; } if(ss != INVALID_SOCKET) { so._shutdown(ss, SHUT_RDWR); so._closesocket(ss); ss = INVALID_SOCKET; } if(clidatasock != INVALID_SOCKET) { so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); clidatasock = INVALID_SOCKET; } if ((clidatasock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);} sasize = sizeof(struct sockaddr_in); if(so._getsockname(param->ctrlsock, (struct sockaddr *)¶m->sinc, &sasize)){RETURN(824);} param->sinc.sin_port = 0; if(so._bind(clidatasock, (struct sockaddr *)¶m->sinc, sasize)){RETURN(822);} if (pasv) { if(so._listen(clidatasock, 1)) {RETURN(823);} if(so._getsockname(clidatasock, (struct sockaddr *)¶m->sinc, &sasize)){RETURN(824);} sprintf((char *)buf, "227 OK (%u,%u,%u,%u,%u,%u)\r\n", (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[0]), (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[1]), (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[2]), (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[3]), (unsigned)(((unsigned char *)(¶m->sinc.sin_port))[0]), (unsigned)(((unsigned char *)(¶m->sinc.sin_port))[1]) ); } else { unsigned long b1, b2, b3, b4; unsigned short b5, b6; if(sscanf((char *)buf+5, "%lu,%lu,%lu,%lu,%hu,%hu", &b1, &b2, &b3, &b4, &b5, &b6)!=6) {RETURN(828);} param->sinc.sin_family = AF_INET; param->sinc.sin_port = htons((unsigned short)((b5<<8)^b6)); param->sinc.sin_addr.s_addr = htonl((b1<<24)^(b2<<16)^(b3<<8)^b4); if(so._connect(clidatasock, (struct sockaddr *)¶m->sinc, sasize)) { so._closesocket(clidatasock); clidatasock = INVALID_SOCKET; RETURN(826); } sprintf(buf, "200 OK\r\n"); } #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlehdrfilterssrv(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(879); } #endif if(socksend(param->ctrlsock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S])!=(int)strlen((char *)buf)) {RETURN (825);} status = 4; } else if (status == 4 && ( !(strncasecmp((char *)buf, "RETR ", 5) && (param->operation = FTP_GET)) || !(strncasecmp((char *)buf, "LIST", 4) && (param->operation = FTP_LIST))|| !(strncasecmp((char *)buf, "NLST ", 5) && (param->operation = FTP_LIST)) || !(strncasecmp((char *)buf, "MLSD", 4) && (param->operation = FTP_LIST)) || !(strncasecmp((char *)buf, "APPE ", 5) && (param->operation = FTP_PUT)) || !(strncasecmp((char *)buf, "STOR ", 5) && (param->operation = FTP_PUT)) )){ int arg = (buf[4] && buf[5])? 1:0; int ressent = 0; #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlehdrfilterscli(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(880); } #endif if(clidatasock == INVALID_SOCKET) { RETURN (829);} if(pasv){ memset(&fds, 0, sizeof(fds)); fds.fd = clidatasock; fds.events = POLLIN; res = so._poll (&fds, 1, conf.timeouts[STRING_L]*1000); if(res != 1) { RETURN(857); } sasize = sizeof(struct sockaddr_in); ss = so._accept(clidatasock, (struct sockaddr *)¶m->sinc, &sasize); if (ss == INVALID_SOCKET) { RETURN (858);} so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); clidatasock = ss; ss = INVALID_SOCKET; } if(clidatasock == INVALID_SOCKET){RETURN(828);} req = mystrdup((char *)buf); buf[4] = 0; status = 3; ss = ftpcommand(param, buf, arg? buf+5 : NULL); if (ss == INVALID_SOCKET) { so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); clidatasock = INVALID_SOCKET; if(socksend(param->ctrlsock, (unsigned char *)"550 err\r\n", 9, conf.timeouts[STRING_S])!=9) {RETURN (831);} continue; } if(socksend(param->ctrlsock, (unsigned char *)"125 data\r\n", 10, conf.timeouts[STRING_S]) != 10) { param->remsock = INVALID_SOCKET; RETURN (832); } if(param->srvoffset < param->srvinbuf)while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', 0)) > 3){ if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN(833);} if(isnumber(*buf) && buf[3] != '-') { ressent = 1; break; } } sc = param->remsock; param->remsock = ss; so._setsockopt(param->remsock, SOL_SOCKET, SO_LINGER, (unsigned char *)&lg, sizeof(lg)); so._setsockopt(clidatasock, SOL_SOCKET, SO_LINGER, (unsigned char *)&lg, sizeof(lg)); param->clisock = clidatasock; res = sockmap(param, conf.timeouts[CONNECTION_S]); if(param->remsock != INVALID_SOCKET) { so._shutdown (param->remsock, SHUT_RDWR); so._closesocket(param->remsock); } if(param->clisock != INVALID_SOCKET) { so._shutdown (param->clisock, SHUT_RDWR); so._closesocket(param->clisock); } param->clisock = param->ctrlsock; param->remsock = sc; sc = INVALID_SOCKET; ss = INVALID_SOCKET; clidatasock = INVALID_SOCKET; if(!ressent){ while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', conf.timeouts[STRING_L])) > 3){ if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN(833);} if(isnumber(*buf) && buf[3] != '-') break; } if(i < 3) {RETURN(834);} } } else { if(status < 3) { if(socksend(param->remsock, (unsigned char *)"530 login\r\n", 11, conf.timeouts[STRING_S])!=1) {RETURN (810);} continue; } if(!strncasecmp((char *)buf, "QUIT", 4)) status = 5; if(!strncasecmp((char *)buf, "CWD ", 4)) req = mystrdup((char *)buf); i = (int)strlen((char *)buf); buf[i++] = '\r'; buf[i++] = '\n'; if(socksend(param->remsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (811);} param->statscli += i; param->nwrites++; while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', conf.timeouts[STRING_L])) > 0){ if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (812);} if(i > 4 && isnumber(*buf) && buf[3] != '-') break; } if(status == 5) {RETURN (0);} if(i < 3) {RETURN (813);} } sasize = sizeof(struct sockaddr_in); if(so._getpeername(param->ctrlsock, (struct sockaddr *)¶m->sinc, &sasize)){RETURN(819);} if(req && (param->statscli || param->statssrv)){ (*param->srv->logfunc)(param, (unsigned char *)req); } } CLEANRET: if(sc != INVALID_SOCKET) { so._shutdown(sc, SHUT_RDWR); so._closesocket(sc); } if(ss != INVALID_SOCKET) { so._shutdown(ss, SHUT_RDWR); so._closesocket(ss); } if(clidatasock != INVALID_SOCKET) { so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); } sasize = sizeof(struct sockaddr_in); so._getpeername(param->ctrlsock, (struct sockaddr *)¶m->sinc, &sasize); if(param->res != 0 || param->statscli || param->statssrv ){ (*param->srv->logfunc)(param, (unsigned char *)((req && (param->res > 802))? req:NULL)); } if(req) myfree(req); if(buf) myfree(buf); freeparam(param); return (NULL); }
void * proxychild(struct clientparam* param) { int res=0, i=0; unsigned char* buf = NULL, *newbuf; int inbuf; int bufsize; unsigned reqlen = 0; unsigned char *sb=NULL, *sg=NULL, *se=NULL, *sp=NULL, *req=NULL, *su=NULL, *ss = NULL; unsigned char *ftpbase=NULL; unsigned char username[1024]; int keepalive = 0; uint64_t contentlength64 = 0; int hascontent =0; int isconnect = 0; int redirect = 0; int prefix = 0, ckeepalive=0; int ftp = 0; int anonymous; int sleeptime = 0; int reqsize, reqbufsize; int authenticate; struct pollfd fds[2]; SOCKET ftps; char ftpbuf[FTPBUFSIZE]; int inftpbuf = 0; #ifndef WITHMAIN FILTER_ACTION action; #endif if(!(buf = myalloc(BUFSIZE))) {RETURN(21);} bufsize = BUFSIZE; anonymous = param->srv->singlepacket; for(;;){ memset(buf, 0, bufsize); inbuf = 0; if(keepalive && (param->cliinbuf == param->clioffset) && (param->remsock != INVALID_SOCKET)){ memset(fds, 0, sizeof(fds)); fds[0].fd = param->clisock; fds[0].events = POLLIN; fds[1].fd = param->remsock; fds[1].events = POLLIN; res = so._poll(fds, 2, conf.timeouts[STRING_S]*1000); if(res<=0) { RETURN(555); } if((fds[1].revents & (POLLIN|POLLHUP|POLLERR|POLLNVAL))) { if(param->transparent || (!param->redirected && param->redirtype == R_HTTP)) RETURN(555); ckeepalive = 0; so._shutdown(param->remsock, SHUT_RDWR); so._closesocket(param->remsock); param->remsock = INVALID_SOCKET; param->redirected = 0; param->redirtype = 0; } } i = sockgetlinebuf(param, CLIENT, buf, LINESIZE - 1, '\n', conf.timeouts[STRING_L]); if(i<=0) { RETURN((keepalive)?555:(i)?507:508); } if (i==2 && buf[0]=='\r' && buf[1]=='\n') continue; buf[i] = 0; if(req) { if(!param->transparent && !param->srv->transparent && param->redirtype != R_HTTP && (i<=prefix || strncasecmp((char *)buf, (char *)req, prefix))){ ckeepalive = 0; if(param->remsock != INVALID_SOCKET){ so._shutdown(param->remsock, SHUT_RDWR); so._closesocket(param->remsock); } param->remsock = INVALID_SOCKET; param->redirected = 0; param->redirtype = 0; } myfree(req); } req = (unsigned char *)mystrdup((char *)buf); if(!req){RETURN(510);} if(i<10) { RETURN(511); } if(buf[i-3] == '1') keepalive = 2; if((isconnect = !strncasecmp((char *)buf, "CONNECT", 7))) keepalive = 2; if ((sb=(unsigned char *)(unsigned char *)strchr((char *)buf, ' ')) == NULL) {RETURN(512);} ss = ++sb; if(!isconnect) { if (!strncasecmp((char *)sb, "http://", 7)) { sb += 7; } else if (!strncasecmp((char *)sb, "ftp://", 6)) { ftp = 1; sb += 6; } else if(*sb == '/') { param->transparent = 1; } else { RETURN (513); } } else { if ((se=(unsigned char *)(unsigned char *)strchr((char *)sb, ' ')) == NULL || sb==se) {RETURN (514);} *se = 0; } if(!param->transparent || isconnect) { if(!isconnect) { if ((se=(unsigned char *)(unsigned char *)strchr((char *)sb, '/')) == NULL || sb==se || !(sg=(unsigned char *)strchr((char *)sb, ' '))) {RETURN (515);} if(se > sg) se=sg; *se = 0; } prefix = (int)(se - buf); su = (unsigned char*)strrchr((char *)sb, '@'); if(su) { su = mystrdup(sb); decodeurl(su, 0); parseconnusername((char *)su, (struct clientparam *)param, 1, (unsigned short)((ftp)?21:80)); myfree(su); } else parsehostname((char *)sb, (struct clientparam *)param, (unsigned short)((ftp)? 21:80)); if(!isconnect){ if(se==sg)*se-- = ' '; *se = '/'; memmove(ss, se, i - (se - sb) + 1); } } reqlen = i = (int)strlen((char *)buf); if(!strncasecmp((char *)buf, "CONNECT", 7))param->operation = HTTP_CONNECT; else if(!strncasecmp((char *)buf, "GET", 3))param->operation = (ftp)?FTP_GET:HTTP_GET; else if(!strncasecmp((char *)buf, "PUT", 3))param->operation = (ftp)?FTP_PUT:HTTP_PUT; else if(!strncasecmp((char *)buf, "POST", 4)||!strncasecmp((char *)buf, "BITS_POST", 9))param->operation = HTTP_POST; else if(!strncasecmp((char *)buf, "HEAD", 4))param->operation = HTTP_HEAD; else param->operation = HTTP_OTHER; do { buf[inbuf+i]=0; /*printf("Got: %s\n", buf+inbuf);*/ #ifndef WITHMAIN if(i > 25 && !param->srv->transparent && (!strncasecmp((char *)(buf+inbuf), "proxy-authorization", 19))){ sb = (unsigned char *)strchr((char *)(buf+inbuf), ':'); if(!sb)continue; ++sb; while(isspace(*sb))sb++; if(!*sb) continue; if(!strncasecmp((char *)sb, "basic", 5)){ sb+=5; while(isspace(*sb))sb++; i = de64(sb, username, 255); if(i<=0)continue; username[i] = 0; sb = (unsigned char *)strchr((char *)username, ':'); if(sb){ *sb = 0; if(param->password)myfree(param->password); param->password = (unsigned char *)mystrdup((char *)sb+1); param->pwtype = 0; } if(param->username)myfree(param->username); param->username = (unsigned char *)mystrdup((char *)username); continue; } #ifndef NOCRYPT if(param->srv->usentlm && !strncasecmp((char *)sb, "ntlm", 4)){ sb+=4; while(isspace(*sb))sb++; i = de64(sb, username, 1023); if(i<=16)continue; username[i] = 0; if(strncasecmp((char *)username, "NTLMSSP", 8)) continue; if(username[8] == 1) { while( (i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, '\n', conf.timeouts[STRING_S])) > 2){ if(i> 15 && (!strncasecmp((char *)(buf), "content-length", 14))){ buf[i]=0; sscanf((char *)buf + 15, "%"PRINTF_INT64_MODIFIER"u", &contentlength64); } } while( contentlength64 > 0 && (i = sockgetlinebuf(param, CLIENT, buf, (BUFSIZE < contentlength64)? BUFSIZE - 1:(int)contentlength64, '\n', conf.timeouts[STRING_S])) > 0){ if ((uint64_t)i > contentlength64) break; contentlength64-=i; } contentlength64 = 0; if(param->password)myfree(param->password); param->password = myalloc(32); param->pwtype = 2; i = (int)strlen(proxy_stringtable[13]); memcpy(buf, proxy_stringtable[13], i); genchallenge(param, (char *)param->password, (char *)buf + i); memcpy(buf + strlen((char *)buf), "\r\n\r\n", 5); socksend(param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]); ckeepalive = keepalive = 1; goto REQUESTEND; } if(username[8] == 3 && param->pwtype == 2 && i>=80) { unsigned offset, len; len = username[20] + (((unsigned)username[21]) << 8); offset = username[24] + (((unsigned)username[25]) << 8); if(len != 24 || len + offset > (unsigned)i) continue; memcpy(param->password + 8, username + offset, 24); len = username[36] + (((unsigned)username[37]) << 8); offset = username[40] + (((unsigned)username[41]) << 8); if(len> 255 || len + offset > (unsigned)i) continue; if(param->username) myfree(param->username); unicode2text((char *)username+offset, (char *)username+offset, (len>>1)); param->username = (unsigned char *)mystrdup((char *)username+offset); } continue; } #endif }