1 /*
2    3APA3A simpliest proxy server
3    (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
4 
5    please read License Agreement
6 
7 */
8 
9 #include "proxy.h"
10 
11 #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
12 #define BUFSIZE 2048
13 
ftpprchild(struct clientparam * param)14 void * ftpprchild(struct clientparam* param) {
15  int i=0, res;
16  unsigned char *buf;
17  unsigned char *se;
18  int status = 0;
19  int inbuf;
20  int pasv = 0;
21  SOCKET sc = INVALID_SOCKET, ss = INVALID_SOCKET, clidatasock = INVALID_SOCKET;
22  SASIZETYPE sasize;
23  char * req = NULL;
24  struct linger lg;
25  struct pollfd fds;
26 
27  if(!(buf = myalloc(BUFSIZE))) RETURN(876);
28  param->ctrlsock = param->clisock;
29  param->operation = CONNECT;
30  lg.l_onoff = 1;
31  lg.l_linger = conf.timeouts[STRING_L];;
32  if(socksend(param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);}
33  for(;;){
34 	i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 10, '\n', conf.timeouts[CONNECTION_S]);
35 	if(!i) {
36 		RETURN(0);
37 	}
38 	if(i<4) {RETURN(802);}
39 	buf[i] = 0;
40 	if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0;
41 	if (req) myfree (req);
42 	req = NULL;
43 
44 	if (!strncasecmp((char *)buf, "OPEN ", 5)){
45 		if(parsehostname((char *)buf+5, param, 21)){RETURN(803);}
46 		if(param->remsock != INVALID_SOCKET) {
47 			so._shutdown(param->remsock, SHUT_RDWR);
48 			so._closesocket(param->remsock);
49 			param->remsock = INVALID_SOCKET;
50 		}
51 		if((res = (*param->srv->authfunc)(param))) {RETURN(res);}
52 		param->ctrlsocksrv = param->remsock;
53 		if(socksend(param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);}
54 		status = 1;
55 	}
56 	else if (!strncasecmp((char *)buf, "USER ", 5)){
57 		if(parseconnusername((char *)buf +5, param, 0, 21)){RETURN(804);}
58 		if(!status){
59 			if((res = (*param->srv->authfunc)(param))) {RETURN(res);}
60 			param->ctrlsocksrv = param->remsock;
61 		}
62 		if(socksend(param->ctrlsock, (unsigned char *)"331 ok\r\n", 8, conf.timeouts[STRING_S])!=8) {RETURN (807);}
63 		status = 2;
64 
65 	}
66 	else if (!strncasecmp((char *)buf, "PASS ", 5)){
67 		param->extpassword = (unsigned char *)mystrdup((char *)buf+5);
68 		inbuf = BUFSIZE;
69 		res = ftplogin(param, (char *)buf, &inbuf);
70 		param->res = res;
71 		if(inbuf && inbuf != BUFSIZE && socksend(param->ctrlsock, buf, inbuf, conf.timeouts[STRING_S])!=inbuf) {RETURN (807);}
72 		if(!res) status = 3;
73 		sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (ntohs(*SAPORT(&param->sinsr))==21)?0:':', ntohs(*SAPORT(&param->sinsr)));
74 		req = mystrdup((char *)buf);
75 #ifndef WITHMAIN
76 		{
77 			int action, reqbufsize, reqsize;
78 			reqbufsize = BUFSIZE;
79 			reqsize = (int)strlen((char *)buf) + 1;
80 
81 			action = handlereqfilters(param, &buf, &reqbufsize, 0, &reqsize);
82 			if(action == HANDLED){
83 				RETURN(0);
84 			}
85 			if(action != PASS) RETURN(877);
86 		}
87 #endif
88 	}
89 	else if (status >= 3 && (
90 			(!strncasecmp((char *)buf, "PASV", 4) && (pasv = 1)) ||
91 			(!strncasecmp((char *)buf, "EPSV", 4) && (pasv = 2)) ||
92 			(!strncasecmp((char *)buf, "PORT ", 5) && !(pasv = 0))
93 		)){
94 #ifndef WITHMAIN
95 		{
96 			int action, reqbufsize, reqsize;
97 			reqbufsize = BUFSIZE;
98 			reqsize = (int)strlen((char *)buf) + 1;
99 
100 			action = handlehdrfilterscli(param, &buf, &reqbufsize, 0, &reqsize);
101 			if(action == HANDLED){
102 				RETURN(0);
103 			}
104 			if(action != PASS) RETURN(878);
105 		}
106 #endif
107 		if(sc != INVALID_SOCKET) {
108 			so._shutdown(sc, SHUT_RDWR);
109 			so._closesocket(sc);
110 			sc = INVALID_SOCKET;
111 		}
112 		if(ss != INVALID_SOCKET) {
113 			so._shutdown(ss, SHUT_RDWR);
114 			so._closesocket(ss);
115 			ss = INVALID_SOCKET;
116 		}
117 		if(clidatasock != INVALID_SOCKET) {
118 			so._shutdown(clidatasock, SHUT_RDWR);
119 			so._closesocket(clidatasock);
120 			clidatasock = INVALID_SOCKET;
121 		}
122 		if ((clidatasock=socket(SASOCK(&param->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
123 		*SAPORT(&param->sincl) = 0;
124 		if(so._bind(clidatasock, (struct sockaddr *)&param->sincl, SASIZE(&param->sincl))){RETURN(822);}
125 		if (pasv) {
126 			if(so._listen(clidatasock, 1)) {RETURN(823);}
127 			sasize = sizeof(param->sincl);
128 			if(so._getsockname(clidatasock, (struct sockaddr *)&param->sincl, &sasize)){RETURN(824);}
129 			if(pasv == 1){
130 				if(*SAFAMILY(&param->sincl) == AF_INET)
131 					sprintf((char *)buf, "227 OK (%u,%u,%u,%u,%u,%u)\r\n",
132 					 (unsigned)(((unsigned char *)(SAADDR(&param->sincl)))[0]),
133 					 (unsigned)(((unsigned char *)(SAADDR(&param->sincl)))[1]),
134 					 (unsigned)(((unsigned char *)(SAADDR(&param->sincl)))[2]),
135 					 (unsigned)(((unsigned char *)(SAADDR(&param->sincl)))[3]),
136 					 (unsigned)(((unsigned char *)(SAPORT(&param->sincl)))[0]),
137 					 (unsigned)(((unsigned char *)(SAPORT(&param->sincl)))[1])
138 					);
139 				else sprintf((char *)buf, "227 OK (127,0,0,1,%u,%u)\r\n",
140 					 (unsigned)(((unsigned char *)(SAPORT(&param->sincl)))[0]),
141 					 (unsigned)(((unsigned char *)(SAPORT(&param->sincl)))[1])
142 					);
143 			}
144 			else {
145 				sprintf((char *)buf, "229 OK (|||%u|)\r\n",
146 					 (unsigned)ntohs(*SAPORT(&param->sincl))
147 					);
148 			}
149 		}
150 		else {
151 			unsigned long b1, b2, b3, b4;
152 			unsigned short b5, b6;
153 
154 			if(sscanf((char *)buf+5, "%lu,%lu,%lu,%lu,%hu,%hu", &b1, &b2, &b3, &b4, &b5, &b6)!=6) {RETURN(828);}
155 			*SAPORT(&param->sincr) = htons((unsigned short)((b5<<8)^b6));
156 			if(connectwithpoll(clidatasock, (struct sockaddr *)&param->sincr, SASIZE(&param->sincr),CONNECT_TO)) {
157 				so._closesocket(clidatasock);
158 				clidatasock = INVALID_SOCKET;
159 				RETURN(826);
160 			}
161 			sprintf((char *)buf, "200 OK\r\n");
162 		}
163 #ifndef WITHMAIN
164 		{
165 			int action, reqbufsize, reqsize;
166 			reqbufsize = BUFSIZE;
167 			reqsize = (int)strlen((char *)buf) + 1;
168 
169 			action = handlehdrfilterssrv(param, &buf, &reqbufsize, 0, &reqsize);
170 			if(action == HANDLED){
171 				RETURN(0);
172 			}
173 			if(action != PASS) RETURN(879);
174 		}
175 #endif
176 		if(socksend(param->ctrlsock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S])!=(int)strlen((char *)buf)) {RETURN (825);}
177 		status = 4;
178 	}
179 	else if (status == 4 && (
180 		!(strncasecmp((char *)buf, "RETR ", 5) && (param->operation = FTP_GET)) ||
181 		!(strncasecmp((char *)buf, "LIST", 4) && (param->operation = FTP_LIST))||
182 		!(strncasecmp((char *)buf, "NLST ", 5) && (param->operation = FTP_LIST)) ||
183 		!(strncasecmp((char *)buf, "MLSD", 4) && (param->operation = FTP_LIST)) ||
184 		!(strncasecmp((char *)buf, "APPE ", 5) && (param->operation = FTP_PUT)) ||
185 		!(strncasecmp((char *)buf, "STOR ", 5) && (param->operation = FTP_PUT))
186 	)){
187 		int arg = (buf[4] && buf[5])? 1:0;
188 		int ressent = 0;
189 
190 
191 #ifndef WITHMAIN
192 		{
193 			int action, reqbufsize, reqsize;
194 			reqbufsize = BUFSIZE;
195 			reqsize = (int)strlen((char *)buf) + 1;
196 
197 			action = handlehdrfilterscli(param, &buf, &reqbufsize, 0, &reqsize);
198 			if(action == HANDLED){
199 				RETURN(0);
200 			}
201 			if(action != PASS) RETURN(880);
202 		}
203 #endif
204 		if(clidatasock == INVALID_SOCKET) { RETURN (829);}
205 		if(pasv){
206 
207 			memset(&fds, 0, sizeof(fds));
208 			fds.fd = clidatasock;
209 			fds.events = POLLIN;
210 
211 			res = so._poll (&fds, 1, conf.timeouts[STRING_L]*1000);
212 			if(res != 1) {
213 				RETURN(857);
214 			}
215 			sasize = sizeof(param->sincr);
216 			ss = so._accept(clidatasock, (struct sockaddr *)&param->sincr, &sasize);
217 			if (ss == INVALID_SOCKET) { RETURN (858);}
218 			so._shutdown(clidatasock, SHUT_RDWR);
219 			so._closesocket(clidatasock);
220 			clidatasock = ss;
221 			ss = INVALID_SOCKET;
222 		}
223 		if(clidatasock == INVALID_SOCKET){RETURN(828);}
224 		req = mystrdup((char *)buf);
225 		buf[4] = 0;
226 		status = 3;
227 		ss = ftpcommand(param, buf, arg? buf+5 : NULL);
228 		if (ss == INVALID_SOCKET) {
229 			so._shutdown(clidatasock, SHUT_RDWR);
230 			so._closesocket(clidatasock);
231 			clidatasock = INVALID_SOCKET;
232 
233 			if(socksend(param->ctrlsock, (unsigned char *)"550 err\r\n", 9, conf.timeouts[STRING_S])!=9) {RETURN (831);}
234 			continue;
235 		}
236 
237 		if(socksend(param->ctrlsock, (unsigned char *)"125 data\r\n", 10, conf.timeouts[STRING_S]) != 10) {
238 			param->remsock = INVALID_SOCKET;
239 			RETURN (832);
240 		}
241 		if(param->srvoffset < param->srvinbuf)while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', 0)) > 3){
242 			if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN(833);}
243 			if(isnumber(*buf) && buf[3] != '-') {
244 				ressent = 1;
245 				break;
246 			}
247 		}
248 		sc = param->remsock;
249 		param->remsock = ss;
250 		so._setsockopt(param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
251 		so._setsockopt(clidatasock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
252 		param->clisock = clidatasock;
253 		res = mapsocket(param, conf.timeouts[CONNECTION_S]);
254 		if(param->remsock != INVALID_SOCKET) {
255 			so._shutdown (param->remsock, SHUT_RDWR);
256 			so._closesocket(param->remsock);
257 		}
258 		if(param->clisock != INVALID_SOCKET) {
259 			so._shutdown (param->clisock, SHUT_RDWR);
260 			so._closesocket(param->clisock);
261 		}
262 		param->clisock = param->ctrlsock;
263 		param->remsock = sc;
264 		sc = INVALID_SOCKET;
265 		ss = INVALID_SOCKET;
266 		clidatasock = INVALID_SOCKET;
267 		if(!ressent){
268 			while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', conf.timeouts[STRING_L])) > 3){
269 				if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN(833);}
270 				if(isnumber(*buf) && buf[3] != '-') break;
271 			}
272 			if(i < 3) {RETURN(834);}
273 		}
274 	}
275 	else {
276 		if(status < 3) {
277 			if(socksend(param->remsock, (unsigned char *)"530 login\r\n", 11, conf.timeouts[STRING_S])!=1) {RETURN (810);}
278 			continue;
279 		}
280 		if(!strncasecmp((char *)buf, "QUIT", 4)) status = 5;
281 		if(!strncasecmp((char *)buf, "CWD ", 4)) req = mystrdup((char *)buf);
282 		i = (int)strlen((char *)buf);
283 		buf[i++] = '\r';
284 		buf[i++] = '\n';
285 		if(socksend(param->remsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (811);}
286  param->statscli64+=(i);
287 		param->nwrites++;
288 		while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', conf.timeouts[STRING_L])) > 0){
289 			if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (812);}
290 			if(i > 4 && isnumber(*buf) && buf[3] != '-') break;
291 		}
292 		if(status == 5) {RETURN (0);}
293 		if(i < 3) {RETURN (813);}
294 	}
295 	sasize = sizeof(param->sincr);
296 	if(so._getpeername(param->ctrlsock, (struct sockaddr *)&param->sincr, &sasize)){RETURN(819);}
297 	if(req && (param->statscli64 || param->statssrv64)){
298 		dolog(param, (unsigned char *)req);
299 	}
300  }
301 
302 CLEANRET:
303 
304  if(sc != INVALID_SOCKET) {
305 	so._shutdown(sc, SHUT_RDWR);
306 	so._closesocket(sc);
307  }
308  if(ss != INVALID_SOCKET) {
309 	so._shutdown(ss, SHUT_RDWR);
310 	so._closesocket(ss);
311  }
312  if(clidatasock != INVALID_SOCKET) {
313 	so._shutdown(clidatasock, SHUT_RDWR);
314 	so._closesocket(clidatasock);
315  }
316  sasize = sizeof(param->sincr);
317  so._getpeername(param->ctrlsock, (struct sockaddr *)&param->sincr, &sasize);
318  if(param->res != 0 || param->statscli64 || param->statssrv64 ){
319 	dolog(param, (unsigned char *)((req && (param->res > 802))? req:NULL));
320  }
321  if(req) myfree(req);
322  if(buf) myfree(buf);
323  freeparam(param);
324  return (NULL);
325 }
326 
327 #ifdef WITHMAIN
328 struct proxydef childdef = {
329 	ftpprchild,
330 	21,
331 	0,
332 	S_FTPPR,
333 	" -hdefault_host[:port] - use this host and port as default if no host specified\n"
334 };
335 #include "proxymain.c"
336 #endif
337