/* 3APA3A simpliest proxy server (c) 2007-2008 by ZARAZA <3APA3A@security.nnov.ru> please read License Agreement */ #include "../../structures.h" #include "FilePlugin.h" #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #ifndef _WINCE #include #else #include #endif #else #include #ifndef O_BINARY #define O_BINARY (0) #endif #endif #ifdef __cplusplus extern "C" { #endif #ifndef _WIN32 #define WINAPI #define fp_size_t size_t #else #define fp_size_t int #endif static struct pluginlink * pl; static pthread_mutex_t file_mutex; unsigned long preview = 0; char path[300]; static int counter = 0; static int timeo = 0; static char * fp_stringtable[] = { /* 0 */ "HTTP/1.0 503 Service Unavailable\r\n" "Proxy-Connection: close\r\n" "Content-type: text/html; charset=us-ascii\r\n" "\r\n" "503 Service Unavailable\r\n" "

503 Service Unavailable

HTTP policy violation: you have no permission to perform this action. Please conatct helpdesk or Administrator.

\r\n", /* 1 */ "421 SMTP policy violation: you have no permission to perform this action. Please conatct helpdesk or Administrator.\r\n", /* 2 */ "421 FTP policy violation: you have no permission to perform this action. Please conatct helpdesk or Administrator.\r\n", NULL }; enum states { STATE_INITIAL = 0, GOT_HTTP_REQUEST, GOT_HTTP_CLI_HDR, GOT_HTTP_SRV_HDR, GOT_HTTP_CLI_HDR2, GOT_HTTP_SRV_HDR2, GOT_HTTP_CLIDATA, GOT_HTTP_SRVDATA, GOT_SMTP_REQ, GOT_SMTP_DATA, GOT_FTP_REQ, GOT_FTP_CLIDATA, GOT_FTP_SRVDATA, FLUSH_DATA }; struct fp_callback { struct fp_callback *next; FP_CALLBACK callback; void * data; int what; int preview_size; int max_size; }; struct fp_stream { struct fp_stream *next; char * buf; int state; int what; int needsrvconnect; int preview_size; long bufsize; unsigned long clihdrwritten, clientwritten, clientsent, srvhdrwritten, serverwritten, serversent; struct fp_callback *callbacks; struct fp_filedata fpd; } *fp_streams = NULL; struct sockfuncs sso; static void genpaths(struct fp_stream *fps){ if(fps->what & (FP_CLIDATA|FP_CLIHEADER)){ if(fps->fpd.path_cli) free(fps->fpd.path_cli); fps->fpd.path_cli = malloc(strlen(path) + 10); sprintf(fps->fpd.path_cli, path, counter++); } if(fps->what & (FP_SRVDATA|FP_SRVHEADER)){ if(fps->fpd.path_srv) free(fps->fpd.path_srv); fps->fpd.path_srv = malloc(strlen(path) + 10); sprintf(fps->fpd.path_srv, path, counter++); } } static #ifdef _WIN32 HANDLE #else int #endif initclientfile(struct fp_stream *fps){ fps->clientwritten = fps->clientsent = 0; #ifdef _WIN32 if(fps->fpd.h_cli != INVALID_HANDLE_VALUE){ CloseHandle(fps->fpd.h_cli); } fps->fpd.h_cli = CreateFile(fps->fpd.path_cli, GENERIC_READ | GENERIC_WRITE, (fps->what & FP_SHAREFILE)? FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE:0, NULL, CREATE_ALWAYS, (fps->what & (FP_KEEPFILE|FP_SHAREFILE))? FILE_ATTRIBUTE_TEMPORARY : FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); return fps->fpd.h_cli; #else if(fps->fpd.fd_cli != -1) close(fps->fpd.fd_cli); fps->fpd.fd_cli = open(fps->fpd.path_cli, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, 0600); return fps->fpd.fd_cli; #endif } static #ifdef _WIN32 HANDLE #else int #endif initserverfile(struct fp_stream *fps){ fps->serverwritten = fps->serversent = 0; #ifdef _WIN32 if(fps->fpd.h_srv != INVALID_HANDLE_VALUE){ CloseHandle(fps->fpd.h_srv); } fps->fpd.h_srv = CreateFile(fps->fpd.path_srv, GENERIC_READ | GENERIC_WRITE, (fps->what & FP_SHAREFILE)? FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE:0, NULL, CREATE_ALWAYS, (fps->what & (FP_KEEPFILE|FP_SHAREFILE))? FILE_ATTRIBUTE_TEMPORARY : FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); return fps->fpd.h_srv; #else if(fps->fpd.fd_srv != -1) close(fps->fpd.fd_srv); fps->fpd.fd_srv = open(fps->fpd.path_srv, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, 0600); return fps->fpd.fd_srv; #endif } static void closefiles(struct fp_stream *fps){ #ifdef _WIN32 if(fps->fpd.h_cli != INVALID_HANDLE_VALUE) { CloseHandle(fps->fpd.h_cli); fps->fpd.h_cli = INVALID_HANDLE_VALUE; if((fps->what & FP_SHAREFILE) && !(fps->what & FP_KEEPFILE)) DeleteFile(fps->fpd.path_cli); } if(fps->fpd.h_srv != INVALID_HANDLE_VALUE) { CloseHandle(fps->fpd.h_srv); fps->fpd.h_srv = INVALID_HANDLE_VALUE; if((fps->what & FP_SHAREFILE) && !(fps->what & FP_KEEPFILE)) DeleteFile(fps->fpd.path_cli); } #else if(fps->fpd.fd_cli != -1) { close(fps->fpd.fd_cli); fps->fpd.fd_cli = -1; if(!(fps->what & FP_KEEPFILE)) unlink(fps->fpd.path_cli); } if(fps->fpd.fd_srv != -1) { close(fps->fpd.fd_srv); fps->fpd.fd_srv = -1; if(!(fps->what & FP_KEEPFILE)) unlink(fps->fpd.path_srv); } #endif if(fps->fpd.path_cli) { free(fps->fpd.path_cli); fps->fpd.path_cli = NULL; } if(fps->fpd.path_srv) { free(fps->fpd.path_srv); fps->fpd.path_srv = NULL; } fps->clihdrwritten = fps->clientwritten = fps->clientsent = fps->srvhdrwritten = fps->serverwritten = fps->serversent = 0; } static int searchsocket(SOCKET s, struct fp_stream **pfps){ struct fp_stream *fps = NULL; int ret = 0; pthread_mutex_lock(&file_mutex); for(fps = fp_streams; fps; fps = fps->next){ if(fps->fpd.cp->clisock == s) { ret = 1; break; } if(fps->fpd.cp->remsock == s) { ret = 2; break; } if(fps->fpd.cp->ctrlsock == s) { ret = 3; break; } } pthread_mutex_unlock(&file_mutex); *pfps = fps; return ret; } static void freecallback(struct fp_stream * fps, struct fp_callback * fpc){ if(fpc->next) freecallback(fps, fpc->next); if(fpc->what & FP_CALLONREMOVE) (*fpc->callback)(FP_CALLONREMOVE, fpc->data, &fps->fpd, NULL, 0); free(fpc); } static void removefps(struct fp_stream * fps){ if(!fp_streams) return; pthread_mutex_lock(&file_mutex); if(fp_streams == fps)fp_streams = fps->next; else { struct fp_stream *fps2; for(fps2 = fp_streams; fps2->next; fps2 = fps2->next){ if(fps2->next == fps){ fps2->next = fps->next; break; } } } pthread_mutex_unlock(&file_mutex); if(fps->callbacks){ freecallback(fps, fps->callbacks); fps->callbacks = 0; } closefiles(fps); if(fps->buf) { free(fps->buf); fps->buf = NULL; } fps->state = 0; } static int WINAPI fp_connect(SOCKET s, const struct sockaddr *name, fp_size_t namelen){ return sso._connect(s, name, namelen); } void processcallbacks(struct fp_stream *fps, int what, char *msg, int size){ struct fp_callback *cb; int state; state = fps->state; if(fps->what & what) { fps->what = 0; for(cb = fps->callbacks; cb; cb=cb->next){ if(cb->what & what){ cb->what = (*cb->callback)(what, cb->data, &(fps->fpd), msg, size); } fps->what |= cb->what; } } if(fps->what & FP_REJECT){ switch(state){ /* Fixme: handle different states */ case GOT_SMTP_REQ: case GOT_SMTP_DATA: fps->state = FLUSH_DATA; pl->socksend(fps->fpd.cp->clisock, fp_stringtable[1], (int)strlen(fp_stringtable[1]), pl->conf->timeouts[STRING_S]); fps->state = state; break; case GOT_HTTP_REQUEST: case GOT_HTTP_CLI_HDR: case GOT_HTTP_SRV_HDR: case GOT_HTTP_CLI_HDR2: case GOT_HTTP_SRV_HDR2: case GOT_HTTP_CLIDATA: case GOT_HTTP_SRVDATA: if(!fps->serversent){ fps->state = FLUSH_DATA; pl->socksend(fps->fpd.cp->clisock, fp_stringtable[0], (int)strlen(fp_stringtable[0]), pl->conf->timeouts[STRING_S]); fps->state = state; } break; case GOT_FTP_CLIDATA: case GOT_FTP_REQ: case GOT_FTP_SRVDATA: fps->state = FLUSH_DATA; pl->socksend(fps->fpd.cp->ctrlsock, fp_stringtable[1], (int)strlen(fp_stringtable[1]), pl->conf->timeouts[STRING_S]); fps->state = state; break; default: break; } if(fps->fpd.cp->remsock != INVALID_SOCKET)sso._closesocket(fps->fpd.cp->remsock); fps->fpd.cp->remsock = INVALID_SOCKET; if(fps->fpd.cp->clisock != INVALID_SOCKET)sso._closesocket(fps->fpd.cp->clisock); fps->fpd.cp->clisock = INVALID_SOCKET; } } static int copyfdtosock(struct fp_stream * fps, DIRECTION which, long len){ int res; long toread; int state; #ifdef _WIN32 HANDLE h; #else int fd; #endif SOCKET sock; long offset; int sendchunk = 0; state = fps->state; fps->state = FLUSH_DATA; if(!fps->buf){ fps->buf = malloc(2048); if(!fps->buf) return -2; fps->bufsize = 2048; } if(which == SERVER){ offset = fps->clientsent; fps->clientsent += len; #ifdef _WIN32 h = fps->fpd.h_cli; #else fd = fps->fpd.fd_cli; #endif sock = fps->fpd.cp->remsock; } else { if(fps->fpd.cp->chunked){ if(fps->serversent < fps->srvhdrwritten && (fps->serversent + len) > fps->srvhdrwritten){ len -= fps->srvhdrwritten - fps->serversent; if ((res = copyfdtosock(fps, which, fps->srvhdrwritten - fps->serversent))) return res; } if(fps->serversent >= fps->srvhdrwritten){ sprintf(fps->buf, "%lx\r\n", len); sendchunk = (int)strlen(fps->buf); if(pl->socksend(fps->fpd.cp->clisock, fps->buf, sendchunk, pl->conf->timeouts[STRING_S]) != sendchunk){ return -4; } } } offset = fps->serversent; fps->serversent += len; #ifdef _WIN32 h = fps->fpd.h_srv; #else fd = fps->fpd.fd_srv; #endif sock = fps->fpd.cp->clisock; } #ifdef _WIN32 if(SetFilePointer(h,offset,0,FILE_BEGIN)!=offset){ return -1; } #else if(lseek(fd, offset, SEEK_SET) < 0) { return -1; } #endif while(len > 0){ /* Fixme: prevent client/server timeouts */ toread = (len > fps->bufsize)? fps->bufsize:len; #ifdef _WIN32 if(!ReadFile(h, fps->buf, (DWORD)toread,(DWORD *)&res,NULL)) { #else if((res = read(fd, fps->buf, toread)) <= 0) { #endif return -3; } if(pl->socksend(sock, fps->buf, res, pl->conf->timeouts[STRING_S]) != res) { return -4; } len -= res; } if(sendchunk){ if(pl->socksend(sock, "\r\n", 2, pl->conf->timeouts[STRING_S]) != 2) return -4; } fps->state = state; return 0; } static int WINAPI fp_poll(struct pollfd *fds, unsigned int nfds, int timeout){ struct fp_stream *fps = NULL; int res; unsigned i; int to; for(i = 0; istate == GOT_SMTP_DATA){ if(fds[i].events & POLLOUT){ fds[i].revents = POLLOUT; return 1; } } else if(res == 2 && (((fps->what & FP_CLIHEADER) && (fps->state == GOT_HTTP_REQUEST || fps->state == GOT_HTTP_CLI_HDR2)) || ((fps->what & FP_CLIDATA) && fps->state == GOT_HTTP_CLIDATA))){ if(fds[i].events & POLLIN){ processcallbacks(fps, (fps->state == GOT_HTTP_CLIDATA)?FP_CLIDATA:FP_CALLAFTERCLIHEADERS, NULL, 0); if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) { if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent)) return -2; } if(fps->state) { if(fps->what & FP_SRVHEADER) initserverfile(fps); fps->state = GOT_HTTP_SRV_HDR; } } else if(fds[i].events & POLLOUT){ fds[i].revents = POLLOUT; return 1; } } else if(res == 1 && (fps->state == GOT_HTTP_SRVDATA || fps->state == GOT_HTTP_SRV_HDR || fps->state == GOT_HTTP_SRV_HDR2)&& (fds[i].events & POLLIN)){ processcallbacks(fps, (fps->state == GOT_HTTP_SRVDATA)? FP_SRVDATA:FP_CALLAFTERSRVHEADERS, NULL, 0); if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) { if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent)) return -2; } closefiles(fps); fps->state = 0; } } return sso._poll(fds, nfds, timeout); } static int WINAPI fp_send(SOCKET s, const char *msg, fp_size_t len, int flags){ struct fp_stream *fps = NULL; int res; res = searchsocket(s, &fps); if(res == 2){ if(fps->state == GOT_SMTP_DATA) { if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) { processcallbacks(fps, FP_CLIDATA, NULL, 0); if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent)) { return -1; } fps->state = 0; } closefiles(fps); fps->state = 0; return sso._send(s, msg, len, flags); } if((((fps->what & FP_CLIHEADER) && (fps->state == GOT_HTTP_REQUEST || fps->state == GOT_HTTP_CLI_HDR2)) || ((fps->what & FP_CLIDATA) && fps->state == GOT_HTTP_CLIDATA))){ #ifdef _WIN32 if(SetFilePointer(fps->fpd.h_cli, fps->clientwritten + fps->clihdrwritten, 0, FILE_BEGIN) != (fps->clientwritten + fps->clihdrwritten)){ return -1; } if(!WriteFile(fps->fpd.h_cli, msg, (DWORD)len,(DWORD *)&res,NULL) || res != len){ return -1; } #else if(lseek(fps->fpd.fd_cli, fps->clientwritten + fps->clihdrwritten, SEEK_SET) < 0) { return -1; } if((res = write(fps->fpd.fd_cli, msg, len) != len)) return -1; #endif if(fps->state == GOT_HTTP_CLIDATA)fps->clientwritten += res; else fps->clihdrwritten += res; return res; } } if(res == 1){ if(((fps->what & FP_SRVDATA) && (fps->state == GOT_HTTP_SRVDATA || fps->state == GOT_HTTP_SRV_HDR) && fps->fpd.cp->chunked && len < 16 )){ int hasnonzero = 0, i; for(i=0; i < len; i++){ char c = msg[i]; if(c == '\r' || c == '\n') continue; if((c<'0'|| c>'9') && (c<'A' || c>'F') && (c<'a' || c>'f')) { return sso._send(s, msg, len, flags); } if(c != '0') hasnonzero = 1; } if(i>2 && !hasnonzero){ if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) { processcallbacks(fps, FP_SRVDATA, NULL, 0); if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent)) { return -1; } fps->state = 0; } closefiles(fps); fps->state = 0; return sso._send(s, msg, len, flags); } return len; } if(((fps->what & FP_SRVHEADER) && (fps->state == GOT_HTTP_SRV_HDR || fps->state == GOT_HTTP_SRV_HDR2))){ #ifdef _WIN32 if(SetFilePointer(fps->fpd.h_srv, fps->serverwritten + fps->srvhdrwritten, 0, FILE_BEGIN) != (fps->serverwritten + fps->srvhdrwritten)){ return -1; } if(!WriteFile(fps->fpd.h_srv, msg, (DWORD)len,(DWORD *)&res,NULL) || res !=len){ return -1; } #else if(lseek(fps->fpd.fd_srv, fps->serverwritten + fps->srvhdrwritten, SEEK_SET) < 0) { return -1; } if((res = write(fps->fpd.fd_srv, msg, len) != len)) return -1; #endif fps->srvhdrwritten += res; return res; } } return sso._send(s, msg, len, flags); } static int WINAPI fp_sendto(SOCKET s, const void *msg, int len, int flags, const struct sockaddr *to, fp_size_t tolen){ struct fp_stream *fps = NULL; int res; res = searchsocket(s, &fps); if(res == 2) { switch(fps->state){ case GOT_SMTP_REQ: if(!(fps->what & FP_CLIDATA)) break; fps->state = GOT_SMTP_DATA; initclientfile(fps); case GOT_FTP_REQ: if(fps->state == GOT_FTP_REQ){ if(!(fps->what & FP_CLIDATA)) break; fps->state = GOT_FTP_CLIDATA; initclientfile(fps); } case GOT_HTTP_CLI_HDR2: if(fps->state == GOT_HTTP_CLI_HDR2){ processcallbacks(fps, FP_CALLAFTERCLIHEADERS, NULL, 0); if ((fps->what & FP_REJECT)) return -1; if((fps->what & FP_CLIDATA) && !(fps->what & FP_CLIHEADER)) initclientfile(fps); else if(!(fps->what & FP_CLIDATA) && (fps->what & FP_CLIHEADER)){ if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) { if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent)) return -2; } } fps->state = GOT_HTTP_CLIDATA; } case GOT_HTTP_REQUEST: if(fps->state == GOT_HTTP_REQUEST && !(fps->what & FP_CLIHEADER)) break; case GOT_SMTP_DATA: case GOT_FTP_CLIDATA: case GOT_FTP_SRVDATA: case GOT_HTTP_CLIDATA: if((!fps->what & FP_CLIDATA)) break; #ifdef _WIN32 if(SetFilePointer(fps->fpd.h_cli, fps->clientwritten + fps->clihdrwritten, 0, FILE_BEGIN) != (fps->clientwritten + fps->clihdrwritten)){ return -1; } if(!WriteFile(fps->fpd.h_cli, msg, (DWORD)len,(DWORD *)&res,NULL) || res != len) { return -1; } #else if(lseek(fps->fpd.fd_cli, fps->clientwritten + fps->clihdrwritten, SEEK_SET) < 0) { return -1; } if((res = write(fps->fpd.fd_cli, msg, len) != len)) return -1; #endif if(fps->state == GOT_HTTP_REQUEST)fps->clihdrwritten += res; else fps->clientwritten += res; if(fps->preview_size && ((fps->clihdrwritten + fps->clientwritten) > (fps->clientsent + fps->preview_size))){ if(!fps->clientsent){ processcallbacks(fps, FP_PREVIEWCLI, NULL, 0); if ((fps->what & FP_REJECT)) return -1; } if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - (fps->clientsent + fps->preview_size))) return -1; } return res; } } else if(res == 1){ switch(fps->state){ case GOT_HTTP_SRV_HDR2: processcallbacks(fps, FP_CALLAFTERSRVHEADERS, NULL, 0); if ((fps->what & FP_REJECT)) return REJECT; if((fps->what & FP_SRVDATA) && !(fps->what & FP_SRVHEADER)) initserverfile(fps); else if(!(fps->what & FP_SRVDATA) && (fps->what & FP_SRVHEADER)){ if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) { if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent)) return -2; } } fps->state = GOT_HTTP_SRVDATA; case GOT_FTP_REQ: if(fps->state == GOT_FTP_REQ){ if(!(fps->what & FP_SRVDATA)) break; fps->state = GOT_FTP_SRVDATA; initserverfile(fps); } case GOT_HTTP_SRV_HDR: if(fps->state == GOT_HTTP_SRV_HDR && !(fps->what & FP_SRVHEADER)) break; case GOT_HTTP_SRVDATA: case GOT_FTP_SRVDATA: case GOT_FTP_CLIDATA: if(!(fps->what & FP_SRVDATA)) break; #ifdef _WIN32 if(SetFilePointer(fps->fpd.h_srv, fps->serverwritten + fps->srvhdrwritten, 0, FILE_BEGIN) != (fps->serverwritten + fps->srvhdrwritten)){ return -1; } if(!WriteFile(fps->fpd.h_srv, msg, (DWORD)len,(DWORD *)&res,NULL) || res != len){ return -1; } #else if(lseek(fps->fpd.fd_srv, fps->serverwritten + fps->srvhdrwritten, SEEK_SET) < 0) { return -1; } if((res = write(fps->fpd.fd_srv, msg, len) != len)) return -1; #endif if(fps->state == GOT_HTTP_SRV_HDR)fps->srvhdrwritten += res; else fps->serverwritten += res; if(fps->preview_size && ((fps->srvhdrwritten + fps->serverwritten) > (fps->serversent + fps->preview_size))){ if(!fps->serversent){ processcallbacks(fps, FP_PREVIEWSRV, NULL, 0); if ((fps->what & FP_REJECT)) return -1; } if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - (fps->serversent + fps->preview_size))) return -1; } return res; } } return sso._sendto(s, msg, len, flags, to, tolen); } static int WINAPI fp_recv(SOCKET s, void *buf, fp_size_t len, int flags){ return sso._recv(s, buf, len, flags); } static int WINAPI fp_recvfrom(SOCKET s, void * buf, fp_size_t len, int flags, struct sockaddr * from, fp_size_t * fromlen){ return sso._recvfrom(s, buf, len, flags, from, fromlen); } static int WINAPI fp_shutdown(SOCKET s, int how){ struct fp_stream *fps = NULL; int res; res = searchsocket(s, &fps); if(res){ if(fps->state == GOT_HTTP_SRV_HDR || fps->state == GOT_HTTP_SRVDATA || fps->state == GOT_FTP_SRVDATA){ if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) { processcallbacks(fps, FP_SRVDATA, NULL, 0); copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent); } closefiles(fps); fps->state = 0; } else if(fps->state == GOT_FTP_CLIDATA){ if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) { processcallbacks(fps, FP_CLIDATA, NULL, 0); copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent); } closefiles(fps); fps->state = 0; } } return sso._shutdown(s, how); } static int WINAPI fp_closesocket(SOCKET s){ return sso._closesocket(s); } struct fp_stream * addfps(struct clientparam *cp){ struct fp_stream *fps; for(fps = fp_streams; fps && fps->fpd.cp != cp; fps = fps->next); if(!fps) { fps = malloc(sizeof(struct fp_stream)); if(!fps){ return NULL; } memset(fps, 0, sizeof(struct fp_stream)); fps->fpd.cp = cp; fps->next = fp_streams; fp_streams = fps; #ifdef _WIN32 fps->fpd.h_cli = fps->fpd.h_srv = INVALID_HANDLE_VALUE; #else fps->fpd.fd_cli = fps->fpd.fd_srv = -1; #endif } return fps; } static int fp_registercallback (int what, int max_size, int preview_size, struct clientparam *cp, FP_CALLBACK cb, void *data){ struct fp_callback * fpc; struct fp_stream *fps; fpc = malloc(sizeof(struct fp_callback)); if(!fpc) return 0; fpc->what = what; fpc->preview_size = preview_size; fpc->max_size = max_size; fpc->data = data; fpc->callback = cb; pthread_mutex_lock(&file_mutex); fps = addfps(cp); if(fps){ fpc->next = fps->callbacks; fps->callbacks = fpc; fps->what |= fpc->what; if(preview_size > fps->preview_size) fps->preview_size = preview_size; } else free(fpc); pthread_mutex_unlock(&file_mutex); return fps?1:0; } static void * fp_open(void * idata, struct srvparam * param){ return idata; } #define FC ((struct fp_stream *)fc) static FILTER_ACTION fp_client(void *fo, struct clientparam * param, void** fc){ pthread_mutex_lock(&file_mutex); (*fc) = (void *)addfps(param); pthread_mutex_unlock(&file_mutex); return CONTINUE; } static FILTER_ACTION fp_request(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){ if(fc && (param->service == S_PROXY)){ if(FC->state) { closefiles(FC); FC->state = 0; } processcallbacks(FC, FP_CALLONREQUEST, *buf_p + offset, *length_p - offset); if(FC->what &FP_REJECT) return REJECT; FC->state = GOT_HTTP_REQUEST; genpaths(FC); if(FC->what & FP_CLIHEADER) initclientfile(FC); } return CONTINUE; } static FILTER_ACTION fp_hcli(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){ if(fc && param->service == S_SMTPP) { processcallbacks(FC, FP_CALLONREQUEST, *buf_p + offset, *length_p - offset); if(FC->what & FP_REJECT) return REJECT; if(!FC->state)genpaths(FC); FC->state = GOT_SMTP_REQ; } if(fc && param->service == S_FTPPR) { processcallbacks(FC, FP_CALLONREQUEST, *buf_p + offset, *length_p - offset); if(FC->what & FP_REJECT) return REJECT; genpaths(FC); FC->state = GOT_FTP_REQ; } return CONTINUE; } static FILTER_ACTION fp_hsrv(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){ if(fc && param->service == S_PROXY && (FC->state == GOT_HTTP_REQUEST || FC->state == GOT_HTTP_CLI_HDR || FC->state == GOT_HTTP_CLIDATA)){ if(FC->what & FP_SRVHEADER) initserverfile(FC); FC->state = GOT_HTTP_SRV_HDR; } return CONTINUE; } static FILTER_ACTION fp_dcli(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){ if(fc && FC->state == GOT_HTTP_REQUEST){ FC->state = GOT_HTTP_CLI_HDR2; } return CONTINUE; } static FILTER_ACTION fp_dsrv(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){ if(fc && (FC->state == GOT_HTTP_REQUEST || FC->state == GOT_HTTP_CLI_HDR || FC->state == GOT_HTTP_CLIDATA || FC->state == GOT_HTTP_CLIDATA || FC->state == GOT_HTTP_SRV_HDR)){ FC->state = GOT_HTTP_SRV_HDR2; } return CONTINUE; } static void fp_clear(void *fc){ removefps(FC); free(fc); } static void fp_close(void *fo){ } static struct filter fp_filter = { NULL, "filefilter", "filefilter", fp_open, fp_client, fp_request, fp_hcli, fp_hsrv, NULL, fp_dcli, fp_dsrv, fp_clear, fp_close, }; static struct symbol fp_symbols[] = { {fp_symbols + 1, "fp_registercallback", (void*) fp_registercallback}, {NULL, "fp_stringtable", (void*) fp_stringtable} }; static int h_cachedir(int argc, unsigned char **argv){ char * dirp; size_t len; dirp = (argc > 1)? argv[1] : getenv("TEMP"); len = strlen(dirp); if(!dirp || !len || len > 200 || strchr(dirp, '%')) { fprintf(stderr, "FilePlugin: invalid directory path: %s\n", dirp); return (1); } #ifdef _WIN32 if(dirp[len-1] == '\\') dirp[len-1] = 0; sprintf(path, "%.256s\\%%07d.tmp", dirp); #else if(dirp[len-1] == '/') dirp[len-1] = 0; sprintf(path, "%.256s/%%07d.tmp", dirp); #endif return 0; } static int h_preview(int argc, unsigned char **argv){ preview = atoi(argv[1]); return 0; } static struct commands file_commandhandlers[] = { {file_commandhandlers + 1, "file_cachedir", h_cachedir, 2, 2}, {NULL, "file_preview", h_preview, 2, 2}, }; static int file_loaded=0; #ifdef WATCOM #pragma aux file_plugin "*" parm caller [ ] value struct float struct routine [eax] modify [eax ecx edx] #undef PLUGINCALL #define PLUGINCALL #endif PLUGINAPI int PLUGINCALL file_plugin (struct pluginlink * pluginlink, int argc, char** argv){ if(!file_loaded){ pthread_mutex_init(&file_mutex, NULL); file_loaded = 1; pl = pluginlink; memcpy(&sso, pl->so, sizeof(struct sockfuncs)); pl->so->_poll = fp_poll; pl->so->_send = fp_send; pl->so->_sendto = fp_sendto; pl->so->_recv = fp_recv; pl->so->_recvfrom = fp_recvfrom; pl->so->_shutdown = fp_shutdown; pl->so->_closesocket = fp_closesocket; fp_filter.next = pl->conf->filters; pl->conf->filters = &fp_filter; fp_symbols[1].next = pl->symbols.next; pl->symbols.next = fp_symbols; file_commandhandlers[1].next = pl->commandhandlers->next; pl->commandhandlers->next = file_commandhandlers; } h_cachedir(0, NULL); preview = 32768; return 0; } #ifdef __cplusplus } #endif