This commit was manufactured by cvs2svn to create branch 'fedora'.
[linux-2.6.git] / net / tux / proto_ftp.c
1 /*
2  * TUX - Integrated Application Protocols Layer and Object Cache
3  *
4  * Copyright (C) 2000, 2001, Ingo Molnar <mingo@redhat.com>
5  *
6  * ftp_proto.c: FTP application protocol support
7  */
8
9 #define __KERNEL_SYSCALLS__
10 #include <net/tux.h>
11
12 /****************************************************************
13  *      This program is free software; you can redistribute it and/or modify
14  *      it under the terms of the GNU General Public License as published by
15  *      the Free Software Foundation; either version 2, or (at your option)
16  *      any later version.
17  *
18  *      This program is distributed in the hope that it will be useful,
19  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *      GNU General Public License for more details.
22  *
23  *      You should have received a copy of the GNU General Public License
24  *      along with this program; if not, write to the Free Software
25  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  *
27  ****************************************************************/
28
29 #define HELLO           "220 Linux/TUX 3.0 FTP server welcomes you!\r\n"
30 #define WRITE_DONE      "226 Transfer complete.\r\n"
31 #define BAD_FILENAME    "550 No such file or directory.\r\n"
32 #define GOOD_DIR        "250 CWD command successful.\r\n"
33 #define LIST_ERR        "503 LIST without PORT! Closing connection.\r\n"
34 #define LIST_ERR_MEM    "503 LIST could not allocate memory! Closing connection.\r\n"
35 #define WRITE_FILE      "150 Opening BINARY mode data connection.\r\n"
36 #define WRITE_LIST      "150 Opening ASCII mode data connection.\r\n"
37 #define RETR_ERR        "503 RETR without PORT! Closing connection.\r\n"
38 #define PORT_OK         "200 PORT command successful.\r\n"
39 #define LOGIN_OK        "230-There are currently %d users logged in, out of %d maximum.\r\n230-Bandwidth served by TUX currently: %d KB/sec\r\n230 TUX Guest login ok.\r\n"
40 #define LOGIN_OK_ONE    "230-There is currently 1 user logged in, out of %d maximum.\r\n230-Bandwidth served by TUX currently: %d KB/sec\r\n230 TUX Guest login ok.\r\n"
41 #define LOGIN_OK_PASS   "230 TUX Guest login ok.\r\n"
42 #define LOGIN_FORBIDDEN "530 Sorry, Login Denied!\r\n"
43 #define TYPE_OK         "200 Type set to I.\r\n"
44 #define BYE             "221 Thank You for using TUX!\r\n"
45 #define NOT_IMPLEMENTED "502 Command not implemented.\r\n"
46 #define CLOSE_2         "221 Cannot handle request, closing connection!\r\n"
47 #define CLOSE           "500 Unknown command.\r\n"
48 #define CLOSE_TIMEOUT   "421 Timeout, closing connection!\r\n"
49 #define LINUX_SYST      "215 UNIX Type: L8, Linux/TUX/3.0\r\n"
50 #define COMMAND_OK      "200 Command OK.\r\n"
51 #define REST_OK         "350 Restart offset OK.\r\n"
52 #define WRITE_ABORTED   "426 Transfer aborted, data connection closed.\r\n"
53 #define SITE            "214 No SITE commands are recognized.\r\n"
54
55 #define INTERVAL 10
56
57 unsigned long last_measurement;
58 unsigned int ftp_bytes_sent;
59 unsigned int ftp_bandwidth;
60
61 static void __update_bandwidth (tux_req_t *req, unsigned int bytes)
62 {
63         /*
64          * Bandwidth measurement. Not completely accurate,
65          * but it's good enough and lightweight enough.
66          */
67         if (jiffies >= last_measurement + INTERVAL*HZ) {
68                 ftp_bandwidth = (ftp_bytes_sent + 1023)/INTERVAL/1024;
69                 ftp_bytes_sent = 0;
70                 last_measurement = jiffies;
71         }
72         if (bytes)
73                 atomic_add(bytes, (atomic_t *)&ftp_bytes_sent);
74         Dprintk("update_bandwidth(%p,%d), bytes_sent: %d, bandwidth: %d.\n",
75                 req, bytes, ftp_bytes_sent, ftp_bandwidth);
76 }
77
78 #define update_bandwidth(req,bytes)                             \
79         do {                                                    \
80                 if (unlikely(tux_ftp_login_message))            \
81                         __update_bandwidth(req, bytes);         \
82         } while (0)
83
84 static inline void __ftp_send_async_message (tux_req_t *req,
85                  const char *message, int status, unsigned int size)
86 {
87         update_bandwidth(req, size);
88         __send_async_message(req, message, status, size, 1);
89 }
90
91 #define ftp_send_async_message(req,str,status) \
92                 __ftp_send_async_message(req,str,status,sizeof(str)-1)
93
94
95 static void ftp_flush_req (tux_req_t *req, int cachemiss)
96 {
97         tux_push_pending(req->sock->sk);
98         add_req_to_workqueue(req);
99 }
100
101 static void ftp_execute_command (tux_req_t *req, int cachemiss);
102
103 static void ftp_lookup_vhost (tux_req_t *req, int cachemiss)
104 {
105         struct dentry *dentry;
106         struct nameidata base;
107         struct vfsmount *mnt = NULL;
108         unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
109         char ip[3+1+3+1+3+1+3 + 2];
110
111         sprintf(ip, "%d.%d.%d.%d", NIPQUAD(inet_sk(req->sock->sk)->rcv_saddr));
112         Dprintk("ftp_lookup_vhost(%p, %d, virtual: %d, host: %s.)\n", 
113                 req, flag, req->virtual, ip);
114
115         base.flags = LOOKUP_FOLLOW|flag;
116         base.last_type = LAST_ROOT;
117         base.dentry = dget(req->proto->main_docroot.dentry);
118         base.mnt = mntget(req->proto->main_docroot.mnt);
119
120         dentry = __tux_lookup(req, ip, &base, &mnt);
121
122         Dprintk("looked up dentry %p.\n", dentry);
123         if (dentry && !IS_ERR(dentry) && !dentry->d_inode)
124                 TUX_BUG();
125
126         if (!dentry || IS_ERR(dentry)) {
127                 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
128                         add_tux_atom(req, ftp_lookup_vhost);
129                         queue_cachemiss(req);
130                         return;
131                 }
132                 goto abort;
133         }
134
135         req->docroot_dentry = dentry;
136         req->docroot_mnt = mnt;
137
138         add_tux_atom(req, ftp_execute_command);
139         add_req_to_workqueue(req);
140         return;
141 abort:
142         if (dentry) {
143                 if (!IS_ERR(dentry))
144                         dput(dentry);
145                 dentry = NULL;
146         }
147         if (mnt) {
148                 if (!IS_ERR(mnt))
149                         mntput(mnt);
150                 mnt = NULL;
151         }
152         req_err(req);
153         add_req_to_workqueue(req);
154 }
155
156 static void ftp_got_request (tux_req_t *req)
157 {
158         add_tux_atom(req, parse_request);
159         add_tux_atom(req, ftp_flush_req);
160         ftp_send_async_message(req, HELLO, 220);
161 }
162
163 #define GOTO_ERR { TDprintk("FTP protocol error at: %s:%d\n", \
164                         __FILE__, __LINE__); goto error; }
165
166 static void zap_data_socket (tux_req_t *req)
167 {
168         if (!req->data_sock)
169                 return;
170         Dprintk("zapping req %p's data socket %p.\n", req, req->data_sock);
171
172         unlink_tux_data_socket(req);
173         sock_release(req->data_sock);
174         req->data_sock = NULL;
175 }
176
177 static int parse_ftp_message (tux_req_t *req, const int total_len)
178 {
179         int comm, comm1 = 0, comm2 = 0, comm3 = 0, comm4 = 0;
180         int newline_pos, i;
181         const char *mess, *curr;
182
183         curr = mess = req->headers;
184
185         Dprintk("FTP parser got %d bytes: --->{%s}<---\n", total_len, curr);
186
187         newline_pos = -1;
188         for (i = 0; i < total_len; i++, curr++) {
189                 if (!*curr)
190                         GOTO_ERR;
191                 if (!(*curr == '\r') || !(*(curr+1) == '\n'))
192                         continue;
193                 newline_pos = i;
194                 break;
195         }
196         Dprintk("Newline pos: %d\n", newline_pos);
197         if (newline_pos == -1) {
198                 Dprintk("incomplete mess on req %p!\n", req);
199                 return 0;
200         }
201         if (newline_pos < 3)
202                 GOTO_ERR;
203
204 #define toup(c) ((((c) >= 'a') && ((c) <= 'z')) ? ((c) + 'A' - 'a') : (c))
205
206 #define STRING_VAL(c1,c2,c3,c4) \
207         (toup(c1) + (toup(c2) << 8) + (toup(c3) << 16) + (toup(c4) << 24))
208
209 #define STRING_VAL_STR(str) \
210                 STRING_VAL(str[0], str[1], str[2], str[3])
211
212         Dprintk("string val (%c%c%c%c): %08x\n",
213                 mess[0], mess[1], mess[2], mess[3],
214                 STRING_VAL_STR(mess));
215
216 #define PARSE_FTP_COMM(c1,c2,c3,c4,name,num)                    \
217         if (STRING_VAL_STR(mess) == STRING_VAL(c1,c2,c3,c4))    \
218         {                                                       \
219                 Dprintk("parsed "#name".\n");                   \
220                 comm##num = FTP_COMM_##name;                    \
221         }
222
223         PARSE_FTP_COMM('A','C','C','T', ACCT,2);
224         PARSE_FTP_COMM('C','D','U','P', CDUP,3);
225         PARSE_FTP_COMM('S','M','N','T', SMNT,4);
226         PARSE_FTP_COMM('Q','U','I','T', QUIT,1);
227         PARSE_FTP_COMM('R','E','I','N', REIN,2);
228         PARSE_FTP_COMM('P','A','S','V', PASV,3);
229         PARSE_FTP_COMM('S','T','R','U', STRU,4); 
230         PARSE_FTP_COMM('S','T','O','R', STOR,2); 
231         PARSE_FTP_COMM('S','T','O','U', STOU,3); 
232         PARSE_FTP_COMM('A','P','P','E', APPE,4); 
233         PARSE_FTP_COMM('A','L','L','O', ALLO,1); 
234         PARSE_FTP_COMM('R','N','F','R', RNFR,2); 
235         PARSE_FTP_COMM('R','N','T','O', RNTO,3); 
236         PARSE_FTP_COMM('A','B','O','R', ABOR,4); 
237         PARSE_FTP_COMM('D','E','L','E', DELE,1); 
238         PARSE_FTP_COMM('R','M','D',' ', RMD, 2); 
239         PARSE_FTP_COMM('M','K','D',' ', MKD, 3); 
240         PARSE_FTP_COMM('P','W','D',' ', PWD, 4); 
241         PARSE_FTP_COMM('S','Y','S','T', SYST,2); 
242         PARSE_FTP_COMM('N','O','O','P', NOOP,3); 
243         PARSE_FTP_COMM('F','E','A','T', FEAT,4); 
244
245         comm = comm1 | comm2 | comm3 | comm4;
246
247         if (comm) {
248                 if (newline_pos != 4)
249                         GOTO_ERR;
250                 req->ftp_command = comm;
251                 goto out;
252         }
253         
254         switch (STRING_VAL(mess[0], mess[1], mess[2], mess[3])) {
255
256 #define PARSE_FTP_COMM_3CHAR(c1,c2,c3,name)                             \
257                 case STRING_VAL(c1,c2,c3,'\r'):                         \
258                 {                                                       \
259                         Dprintk("parsed "#name".\n");                   \
260                         req->ftp_command = FTP_COMM_##name;             \
261                         if (newline_pos != 3)                           \
262                                 GOTO_ERR;                               \
263                 }
264
265 #define PARSE_FTP_3CHAR_COMM_IGNORE(c1,c2,c3,name)                      \
266                 case STRING_VAL(c1,c2,c3,' '):                          \
267                 {                                                       \
268                         Dprintk("parsed "#name".\n");                   \
269                         req->ftp_command = FTP_COMM_##name;             \
270                 }
271
272 #define PARSE_FTP_COMM_IGNORE(c1,c2,c3,c4,name)                         \
273                 case STRING_VAL(c1,c2,c3,c4):                           \
274                 {                                                       \
275                         Dprintk("parsed "#name".\n");                   \
276                         req->ftp_command = FTP_COMM_##name;             \
277                 }
278
279 #define PARSE_FTP_3CHAR_COMM_1_FIELD(c1,c2,c3,name,field,field_len,max) \
280                 case STRING_VAL(c1,c2,c3,' '):                          \
281                 {                                                       \
282                         Dprintk("parsed "#name".\n");                   \
283                         req->ftp_command = FTP_COMM_##name;             \
284                         if (newline_pos == 4)                           \
285                                 GOTO_ERR;                               \
286                         if (newline_pos >= 5) {                         \
287                                 curr = mess + 3;                        \
288                                 if (*curr++ != ' ')                     \
289                                         GOTO_ERR;                       \
290                                 *(field_len) = newline_pos-4;           \
291                                 if (*(field_len) >= max)                \
292                                         GOTO_ERR;                       \
293                                 memcpy(field, curr, *(field_len));      \
294                                 (field)[*(field_len)] = 0;              \
295                         }                                               \
296                 }
297
298 #define PARSE_FTP_COMM_1_FIELD(c1,c2,c3,c4,name,field,field_len,max)    \
299                 case STRING_VAL(c1,c2,c3,c4):                           \
300                 {                                                       \
301                         Dprintk("parsed "#name".\n");                   \
302                         req->ftp_command = FTP_COMM_##name;             \
303                         if (newline_pos < 4)                            \
304                                 GOTO_ERR;                               \
305                         if (newline_pos == 4)                           \
306                                 *(field_len) = 0;                       \
307                         else {                                          \
308                                 curr = mess + 4;                        \
309                                 if (*curr++ != ' ')                     \
310                                         GOTO_ERR;                       \
311                                 *(field_len) = newline_pos-5;           \
312                                 if (*(field_len) >= max)                \
313                                         GOTO_ERR;                       \
314                                 memcpy(field, curr, *(field_len));      \
315                                 (field)[*(field_len)] = 0;              \
316                         }                                               \
317                 }
318
319                 PARSE_FTP_COMM_1_FIELD('U','S','E','R', USER,
320                         req->username, &req->username_len,
321                         MAX_USERNAME_LEN-1);
322                 if (!req->username_len)
323                         GOTO_ERR;
324                 break;
325
326                 {
327                         #define MAX_PASS_LEN 100
328                         char pass[MAX_PASS_LEN];
329                         unsigned int pass_len;
330                         PARSE_FTP_COMM_1_FIELD('P','A','S','S', PASS,
331                                 pass, &pass_len,
332                                 MAX_PASS_LEN-1);
333                         if (!pass_len)
334                                 GOTO_ERR;
335                         break;
336                 }
337
338                 PARSE_FTP_3CHAR_COMM_1_FIELD('C','W','D', CWD,
339                         req->objectname, &req->objectname_len,
340                         MAX_OBJECTNAME_LEN-1);
341                 if (!req->objectname_len)
342                         GOTO_ERR;
343                 req->uri_str = req->objectname;
344                 req->uri_len = req->objectname_len;
345                 break;
346
347                 PARSE_FTP_COMM_3CHAR('P','W','D', PWD); break;
348
349                 {
350                         char type[3];
351                         unsigned int type_len;
352
353                         PARSE_FTP_COMM_1_FIELD('T','Y','P','E', TYPE,
354                                 type, &type_len, 2);
355                         if (!type_len)
356                                 GOTO_ERR;
357                         if ((type[0] != 'I') && (type[0] != 'A'))
358                                 GOTO_ERR;
359                 }
360                 break;
361
362                 PARSE_FTP_COMM_1_FIELD('R','E','T','R', RETR,
363                         req->objectname, &req->objectname_len,
364                         MAX_OBJECTNAME_LEN-1);
365                 if (!req->objectname_len) {
366                         zap_data_socket(req);
367                         req->ftp_command = FTP_COMM_NONE;
368                 }
369                 req->uri_str = req->objectname;
370                 req->uri_len = req->objectname_len;
371                 break;
372
373                 PARSE_FTP_COMM_1_FIELD('S','I','Z','E', SIZE,
374                         req->objectname, &req->objectname_len,
375                         MAX_OBJECTNAME_LEN-1);
376                 if (!req->objectname_len)
377                         req->ftp_command = FTP_COMM_NONE;
378                 req->uri_str = req->objectname;
379                 req->uri_len = req->objectname_len;
380                 break;
381
382                 PARSE_FTP_COMM_1_FIELD('M','D','T','M', MDTM,
383                         req->objectname, &req->objectname_len,
384                         MAX_OBJECTNAME_LEN-1);
385                 if (!req->objectname_len)
386                         req->ftp_command = FTP_COMM_NONE;
387                 req->uri_str = req->objectname;
388                 req->uri_len = req->objectname_len;
389                 break;
390
391                 PARSE_FTP_COMM_IGNORE('M','O','D','E', MODE);
392                 break;
393
394                 PARSE_FTP_COMM_IGNORE('S','T','A','T', STAT);
395                 break;
396
397                 PARSE_FTP_COMM_IGNORE('S','I','T','E', SITE);
398                 break;
399
400                 PARSE_FTP_COMM_1_FIELD('L','I','S','T', LIST,
401                         req->objectname, &req->objectname_len,
402                         MAX_OBJECTNAME_LEN-1);
403                 if (req->objectname[0] == '-') {
404                         req->objectname_len = 0;
405                         req->objectname[0] = 0;
406                 }
407                 if (req->objectname_len) {
408                         req->uri_str = req->objectname;
409                         req->uri_len = req->objectname_len;
410                 }
411                 break;
412
413                 PARSE_FTP_COMM_1_FIELD('N','L','S','T', NLST,
414                         req->objectname, &req->objectname_len,
415                         MAX_OBJECTNAME_LEN-1);
416                 if (req->objectname[0] == '-') {
417                         req->objectname_len = 0;
418                         req->objectname[0] = 0;
419                 }
420                 if (req->objectname_len) {
421                         req->uri_str = req->objectname;
422                         req->uri_len = req->objectname_len;
423                 }
424                 break;
425
426                 PARSE_FTP_COMM_IGNORE('H','E','L','P', HELP);
427                 break;
428
429                 PARSE_FTP_COMM_IGNORE('C','L','N','T', CLNT);
430                 break;
431
432 #define IS_NUM(n) (((n) >= '0') && ((n) <= '9'))
433
434 #define GET_DIGIT(curr,n)                               \
435         n += (*curr) - '0';                             \
436         curr++;                                         \
437         if (IS_NUM(*curr)) {                            \
438                 n *= 10;
439
440 #define PARSE_PORTNUM(curr,n)                           \
441 do {                                                    \
442         Dprintk("PORT NUM parser:--->{%s}<---\n", curr);\
443         if (!IS_NUM(*curr))                             \
444                 GOTO_ERR;                               \
445         n = 0;                                          \
446         GET_DIGIT(curr,n);                              \
447         GET_DIGIT(curr,n);                              \
448         GET_DIGIT(curr,n);                              \
449         }}}                                             \
450         if (n > 255)                                    \
451                 GOTO_ERR;                               \
452         Dprintk("PORT NUM parser:--->{%s}<---\n", curr);\
453         Dprintk("PORT NUM parser parsed %d.\n", n);     \
454 } while (0)
455
456 #define PARSE_NUM(curr,n)                               \
457 do {                                                    \
458         Dprintk("NUM parser:--->{%s}<---\n", curr);     \
459         if (!IS_NUM(*curr))                             \
460                 GOTO_ERR;                               \
461         n = 0;                                          \
462         GET_DIGIT(curr,n);                              \
463         GET_DIGIT(curr,n);                              \
464         GET_DIGIT(curr,n);                              \
465         GET_DIGIT(curr,n);                              \
466         GET_DIGIT(curr,n);                              \
467         GET_DIGIT(curr,n);                              \
468         GET_DIGIT(curr,n);                              \
469         GET_DIGIT(curr,n);                              \
470         GET_DIGIT(curr,n);                              \
471         GET_DIGIT(curr,n);                              \
472         }}}}}}}}}}                                      \
473         Dprintk("NUM parser:--->{%s}<---\n", curr);     \
474         Dprintk("NUM parser parsed %d.\n", n);          \
475 } while (0)
476
477                 case STRING_VAL('P','O','R','T'):
478                 {
479                         unsigned int h1, h2, h3, h4, p1, p2;
480                         if (req->data_sock)
481                                 zap_data_socket(req);
482                         /*
483                          * Minimum size: "PORT 0,0,0,0,0,0", 16 bytes.
484                          */
485                         if (newline_pos < 16)
486                                 GOTO_ERR;
487                         Dprintk("parsed PORT.\n");
488                         if (req->data_sock)
489                                 GOTO_ERR;
490                         curr = mess + 4;
491                         if (*curr++ != ' ')
492                                 GOTO_ERR;
493                         PARSE_PORTNUM(curr,h1);
494                         if (*curr++ != ',')
495                                 GOTO_ERR;
496                         PARSE_PORTNUM(curr,h2);
497                         if (*curr++ != ',')
498                                 GOTO_ERR;
499                         PARSE_PORTNUM(curr,h3);
500                         if (*curr++ != ',')
501                                 GOTO_ERR;
502                         PARSE_PORTNUM(curr,h4);
503                         if (*curr++ != ',')
504                                 GOTO_ERR;
505                         PARSE_PORTNUM(curr,p1);
506                         if (*curr++ != ',')
507                                 GOTO_ERR;
508                         PARSE_PORTNUM(curr,p2);
509                         if (curr-mess != newline_pos)
510                                 GOTO_ERR;
511                         req->ftp_command = FTP_COMM_PORT;
512                         req->ftp_user_addr = (h1<<24) + (h2<<16) + (h3<<8) + h4;
513                         req->ftp_user_port = (p1<<8) + p2;
514                         Dprintk("FTP PORT got: %d.%d.%d.%d:%d.\n",
515                                 h1, h2, h3, h4, req->ftp_user_port);
516                         Dprintk("FTP user-addr: %08x (htonl: %08x), socket: %08x.\n",
517                                 req->ftp_user_addr, htonl(req->ftp_user_addr),
518                                 inet_sk(req->sock->sk)->daddr);
519                         /*
520                          * Do not allow redirection of connections, and do
521                          * not allow reserved ports to be accessed.
522                          */
523                         if (inet_sk(req->sock->sk)->daddr != htonl(req->ftp_user_addr))
524                                 GOTO_ERR;
525                         if (req->ftp_user_port < 1024)
526                                 GOTO_ERR;
527                         break;
528                 }
529                 case STRING_VAL('R','E','S','T'):
530                 {
531                         unsigned int offset;
532
533                         /*
534                          * Minimum size: "REST 0", 6 bytes.
535                          */
536                         if (newline_pos < 6)
537                                 GOTO_ERR;
538                         Dprintk("parsed REST.\n");
539                         curr = mess + 4;
540                         if (*curr++ != ' ')
541                                 GOTO_ERR;
542                         PARSE_NUM(curr,offset);
543                         if (curr-mess != newline_pos)
544                                 GOTO_ERR;
545                         req->ftp_command = FTP_COMM_REST;
546                         req->ftp_offset_start = offset;
547                         Dprintk("FTP REST got: %d bytes offset.\n", offset);
548
549                         break;
550                 }
551                 default:
552                         req->ftp_command = FTP_COMM_NONE;
553                         break;
554         }
555
556 out:
557         req->parsed_len = newline_pos + 2;
558
559         req->virtual = tux_ftp_virtual_server;
560         if (req->virtual)
561                 add_tux_atom(req, ftp_lookup_vhost);
562         else {
563                 req->docroot_dentry = dget(req->proto->main_docroot.dentry);
564                 req->docroot_mnt = mntget(req->proto->main_docroot.mnt);
565                 add_tux_atom(req, ftp_execute_command);
566         }
567
568         return req->parsed_len;
569 error:
570         clear_keepalive(req);
571         TDprintk("rejecting FTP session!\n");
572         TDprintk("mess     :--->{%s}<---\n", mess);
573         TDprintk("mess left:--->{%s}<---\n", curr);
574         req_err(req);
575         return -1;
576 }
577
578 static void ftp_wait_close (tux_req_t *req, int cachemiss);
579 static void ftp_wait_syn (tux_req_t *req, int cachemiss);
580
581 static int ftp_check_req_err (tux_req_t *req, int cachemiss)
582 {
583         int state = req->sock->sk->sk_state;
584         int err = req->sock->sk->sk_err | req->error;
585         int urg = tcp_sk(req->sock->sk)->urg_data;
586
587         if (req->data_sock) {
588                 urg |= tcp_sk(req->data_sock->sk)->urg_data;
589                 state |= req->data_sock->sk->sk_state;
590                 err |= req->data_sock->sk->sk_err;
591         }
592
593         if ((state <= TCP_SYN_RECV) && !err) {
594                 if (!urg)
595                         return 0;
596                 req->in_file.f_pos = 0;
597                 add_tux_atom(req, flush_request);
598                 zap_data_socket(req);
599                 ftp_send_async_message(req, WRITE_ABORTED, 426);
600                 return 1;
601         }
602 #if CONFIG_TUX_DEBUG
603         req->bytes_expected = 0;
604         if (tux_TDprintk)
605                 dump_stack();
606 #endif
607         req->in_file.f_pos = 0;
608         TDprintk("zapping, data sock state: %d (err: %d, urg: %d)\n",
609                 state, err, urg);
610         /*
611          * We are in the middle of a file transfer,
612          * zap it immediately:
613          */
614         req->error = TUX_ERROR_CONN_CLOSE;
615         zap_request(req, cachemiss);
616         return 1;
617 }
618
619 void ftp_send_file (tux_req_t *req, int cachemiss)
620 {
621         int ret;
622
623         SET_TIMESTAMP(req->output_timestamp);
624 repeat:
625         ret = generic_send_file(req, req->data_sock, cachemiss);
626         update_bandwidth(req, req->in_file.f_pos - req->prev_pos);
627         req->prev_pos = req->in_file.f_pos;
628
629         switch (ret) {
630                 case -5:
631                         add_tux_atom(req, ftp_send_file);
632                         output_timeout(req);
633                         break;
634                 case -4:
635                         add_tux_atom(req, ftp_send_file);
636                         if (add_output_space_event(req, req->data_sock)) {
637                                 del_tux_atom(req);
638                                 goto repeat;
639                         }
640                         break;
641                 case -3:
642                         add_tux_atom(req, ftp_send_file);
643                         queue_cachemiss(req);
644                         break;
645                 case -1:
646                         break;
647                 default:
648                         req->in_file.f_pos = 0;
649
650                         if (tux_ftp_wait_close) {
651                                 req->data_sock->ops->shutdown(req->data_sock, SEND_SHUTDOWN);
652                                 add_tux_atom(req, ftp_wait_close);
653                                 add_req_to_workqueue(req);
654                                 return;
655                         }
656                         Dprintk("FTP send file req %p finished!\n", req);
657                         zap_data_socket(req);
658                         add_tux_atom(req, ftp_flush_req);
659                         if (req->error)
660                                 ftp_send_async_message(req, BAD_FILENAME, 200);
661                         else
662                                 ftp_send_async_message(req, WRITE_DONE, 200);
663                         break;
664         }
665 }
666
667 #define sk_syn(sk) \
668         (!(sk)->sk_err && ((1 << (sk)->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)))
669 #define req_syn(req) \
670         (!(req)->error && sk_syn((req)->data_sock->sk))
671
672 static void ftp_wait_syn (tux_req_t *req, int cachemiss)
673 {
674         Dprintk("ftp_wait_syn in: data socket state %d.\n", req->data_sock->state);
675         if (req_syn(req)) {
676                 spin_lock_irq(&req->ti->work_lock);
677                 add_keepalive_timer(req);
678                 if (test_and_set_bit(0, &req->idle_input))
679                         TUX_BUG();
680                 spin_unlock_irq(&req->ti->work_lock);
681                 if (req_syn(req)) {
682                         add_tux_atom(req, ftp_wait_syn);
683                         return;
684                 }
685                 unidle_req(req);
686         }
687         Dprintk("ftp_wait_syn out: data socket state %d.\n", req->data_sock->state);
688         add_req_to_workqueue(req);
689 }
690
691 static void ftp_wait_close (tux_req_t *req, int cachemiss)
692 {
693         struct sock *sk = req->data_sock->sk;
694
695         Dprintk("ftp_wait_close: data socket state %d.\n", sk->sk_state);
696
697         if (!req->error && (sk->sk_state <= TCP_FIN_WAIT1) && !sk->sk_err) {
698                 spin_lock_irq(&req->ti->work_lock);
699                 add_keepalive_timer(req);
700                 if (test_and_set_bit(0, &req->idle_input))
701                         TUX_BUG();
702                 spin_unlock_irq(&req->ti->work_lock);
703                 if (!req->error && (sk->sk_state <= TCP_FIN_WAIT1) && !sk->sk_err) {
704                         add_tux_atom(req, ftp_wait_close);
705                         return;
706                 }
707                 unidle_req(req);
708         }
709         zap_data_socket(req);
710         add_tux_atom(req, ftp_flush_req);
711         if (req->error)
712                 ftp_send_async_message(req, BAD_FILENAME, 200);
713         else
714                 ftp_send_async_message(req, WRITE_DONE, 200);
715 }
716
717 void ftp_get_size (tux_req_t *req, int cachemiss)
718 {
719         char file_size[200];
720         int missed, len;
721
722         if (!req->dentry) {
723                 missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC);
724                 if (!missed && !req->dentry) {
725                         ftp_send_async_message(req, BAD_FILENAME, 200);
726                         return;
727                 }
728                 if (missed) {
729                         if (cachemiss)
730                                 TUX_BUG();
731                         add_tux_atom(req, ftp_get_size);
732                         queue_cachemiss(req);
733                         return;
734                 }
735         }
736         req->in_file.f_pos = 0;
737         len = sprintf(file_size, "213 %Li\r\n", req->dentry->d_inode->i_size);
738         __ftp_send_async_message(req, file_size, 200, len);
739 }
740
741 void ftp_get_mdtm (tux_req_t *req, int cachemiss)
742 {
743         unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
744         struct dentry *dentry;
745         struct vfsmount *mnt = NULL;
746         char file_mdtm[200];
747         unsigned int len;
748         int err;
749
750         dentry = tux_lookup(req, req->objectname, flag, &mnt);
751         if (!dentry || IS_ERR(dentry)) {
752                 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
753                         if (cachemiss)
754                                 TUX_BUG();
755                         add_tux_atom(req, ftp_get_mdtm);
756                         queue_cachemiss(req);
757                         return;
758                 }
759                 goto out_err;
760         }
761         err = permission(dentry->d_inode, MAY_READ, NULL);
762         if (err)
763                 goto out_err_put;
764
765         req->in_file.f_pos = 0;
766         len = mdtm_time (file_mdtm, dentry->d_inode->i_mtime.tv_sec);
767         dput(dentry);
768         mntput(mnt);
769         __ftp_send_async_message(req, file_mdtm, 200, len);
770         return;
771
772 out_err_put:
773         dput(dentry);
774         mntput(mnt);
775 out_err:
776         ftp_send_async_message(req, BAD_FILENAME, 550);
777 }
778
779 static void ftp_get_file (tux_req_t *req, int cachemiss)
780 {
781         int missed;
782
783         if (!req->dentry) {
784                 missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC);
785                 if (!missed && !req->dentry) {
786                         ftp_send_async_message(req, BAD_FILENAME, 200);
787                         return;
788                 }
789                 if (missed) {
790                         if (cachemiss)
791                                 TUX_BUG();
792                         add_tux_atom(req, ftp_get_file);
793                         queue_cachemiss(req);
794                         return;
795                 }
796         }
797         Dprintk("ftp_send_file %p, ftp_offset: %Ld, total_len: %Ld.\n", req, req->ftp_offset_start, req->total_file_len);
798         req->in_file.f_pos = 0;
799         if (req->ftp_offset_start) {
800                 if (req->ftp_offset_start <= req->total_file_len) {
801                         req->offset_start = req->ftp_offset_start;
802                         req->in_file.f_pos = req->offset_start;
803                 }
804                 req->ftp_offset_start = 0;
805         }
806         req->output_len = req->total_file_len - req->offset_start;
807         req->prev_pos = req->in_file.f_pos;
808         Dprintk("ftp_send_file %p, f_pos: %Ld (out_len: %Ld).\n", req, req->in_file.f_pos, req->output_len);
809         add_tux_atom(req, ftp_send_file);
810         add_tux_atom(req, ftp_wait_syn);
811         add_tux_atom(req, ftp_flush_req);
812         ftp_send_async_message(req, WRITE_FILE, 200);
813 }
814
815 static void __exchange_sockets (tux_req_t *req)
816 {
817         struct socket *tmp;
818
819         tmp = req->data_sock;
820         req->data_sock = req->sock;
821         req->sock = tmp;
822
823         req->in_file.f_pos = 0;
824 }
825
826 static void ftp_do_ls_start (tux_req_t *req, int cachemiss)
827 {
828         Dprintk("ftp_do_ls_start(%p, %d).\n", req, cachemiss);
829         if (!req->cwd_dentry)
830                 TUX_BUG();
831         __exchange_sockets(req);
832         queue_cachemiss(req);
833 }
834
835 static void ftp_do_ls_end (tux_req_t *req, int cachemiss)
836 {
837         Dprintk("ftp_do_ls_end(%p, %d).\n", req, cachemiss);
838         __exchange_sockets(req);
839         if (tux_ftp_wait_close) {
840                 req->data_sock->ops->shutdown(req->data_sock, SEND_SHUTDOWN);
841                 add_tux_atom(req, ftp_wait_close);
842                 add_req_to_workqueue(req);
843                 return;
844         }
845         zap_data_socket(req);
846         add_tux_atom(req, ftp_flush_req);
847         if (req->error)
848                 ftp_send_async_message(req, BAD_FILENAME, 200);
849         else
850                 ftp_send_async_message(req, WRITE_DONE, 200);
851 }
852
853 static void ftp_chdir (tux_req_t *req, int cachemiss)
854 {
855         unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
856         struct dentry *dentry;
857         struct vfsmount *mnt = NULL;
858         int err;
859
860         Dprintk("ftp_chdir(%p, %d, {%s})\n", req, cachemiss, req->objectname);
861         dentry = tux_lookup(req, req->objectname, flag, &mnt);
862         if (!dentry || IS_ERR(dentry)) {
863                 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
864                         if (cachemiss)
865                                 TUX_BUG();
866                         add_tux_atom(req, ftp_chdir);
867                         queue_cachemiss(req);
868                         return;
869                 }
870                 goto out_err;
871         }
872         err = permission(dentry->d_inode, MAY_EXEC, NULL);
873         if (err)
874                 goto out_err_put;
875         req->cwd_dentry = dentry;
876         req->cwd_mnt = mnt;
877         ftp_send_async_message(req, GOOD_DIR, 200);
878         return;
879
880 out_err_put:
881         dput(dentry);
882         mntput(mnt);
883 out_err:
884         ftp_send_async_message(req, BAD_FILENAME, 550);
885 }
886
887 void ftp_accept_pasv (tux_req_t *req, int cachemiss)
888 {
889         struct socket *sock, *new_sock = NULL;
890         struct tcp_opt *tp1, *tp2;
891         int err;
892
893         tp1 = tcp_sk(req->data_sock->sk);
894
895         Dprintk("PASV accept on req %p, accept_queue: %p.\n",
896                         req, tp1->accept_queue);
897         if (req->error || (req->data_sock->sk->sk_state != TCP_LISTEN))
898                 goto error;
899 new_socket:
900         if (!tp1->accept_queue) {
901                 spin_lock_irq(&req->ti->work_lock);
902                 add_keepalive_timer(req);
903                 if (test_and_set_bit(0, &req->idle_input))
904                         TUX_BUG();
905                 spin_unlock_irq(&req->ti->work_lock);
906                 if (!tp1->accept_queue) {
907                         add_tux_atom(req, ftp_accept_pasv);
908                         return;
909                 }
910                 unidle_req(req);
911         }
912         new_sock = sock_alloc();
913         if (!new_sock)
914                 goto error;
915         sock = req->data_sock;
916         new_sock->type = sock->type;
917         new_sock->ops = sock->ops;
918
919         err = sock->ops->accept(sock, new_sock, O_NONBLOCK);
920         Dprintk("PASV accept() returned %d (state %d).\n", err, new_sock->sk->sk_state);
921         if (err < 0)
922                 goto error;
923         if (new_sock->sk->sk_state != TCP_ESTABLISHED)
924                 goto error;
925         /*
926          * Do not allow other clients to steal the FTP connection!
927          */
928         if (inet_sk(new_sock->sk)->daddr != inet_sk(req->sock->sk)->daddr) {
929                 Dprintk("PASV: ugh, unauthorized connect?\n");
930                 sock_release(new_sock);
931                 new_sock = NULL;
932                 goto new_socket;
933         }
934         /*
935          * Zap the listen socket:
936          */
937         zap_data_socket(req);
938
939         tp2 = tcp_sk(new_sock->sk);
940         tp2->nonagle = 2;
941         tp2->ack.pingpong = tux_ack_pingpong;
942         new_sock->sk->sk_reuse = 1;
943         sock_set_flag(new_sock->sk, SOCK_URGINLINE);
944         sock_reset_flag(new_sock->sk, SOCK_LINGER);
945
946         link_tux_data_socket(req, new_sock);
947         add_req_to_workqueue(req);
948         return;
949
950 error:
951         if (new_sock)
952                 sock_release(new_sock);
953         req_err(req);
954         zap_data_socket(req);
955         ftp_send_async_message(req, CLOSE, 500);
956 }
957
958 static char * ftp_print_dir_line (tux_req_t *req, char *tmp, char *d_name, int d_len, int d_type, struct dentry *dentry, struct inode *inode)
959 {
960         char *string0 = tmp;
961         unsigned int size;
962
963         if (req->ftp_command == FTP_COMM_NLST) {
964                 memcpy(tmp, d_name, d_len);
965                 tmp += d_len;
966                 *tmp++ = '\r';
967                 *tmp++ = '\n';
968                 *tmp = 0;
969                 return tmp;
970         }
971         switch (d_type) {
972                 default:
973                 case DT_UNKNOWN:
974                 case DT_WHT:
975                         if (tux_hide_unreadable)
976                                 goto out_dput;
977                         *tmp++ = '?';
978                         break;
979
980                 case DT_FIFO:
981                         if (tux_hide_unreadable)
982                                 goto out_dput;
983                         *tmp++ = 'p';
984                         break;
985
986                 case DT_CHR:
987                         if (tux_hide_unreadable)
988                                 goto out_dput;
989                         *tmp++ = 'c';
990                         break;
991
992                 case DT_DIR:
993                         *tmp++ = 'd';
994                         break;
995
996                 case DT_BLK:
997                         if (tux_hide_unreadable)
998                                 goto out_dput;
999                         *tmp++ = 'b';
1000                         break;
1001
1002                 case DT_REG:
1003                         *tmp++ = '-';
1004                         break;
1005
1006                 case DT_LNK:
1007                         *tmp++ = 'l';
1008                         break;
1009
1010                 case DT_SOCK:
1011                         if (tux_hide_unreadable)
1012                                 goto out_dput;
1013                         *tmp++ = 's';
1014                         break;
1015         }
1016
1017         if (inode->i_mode & S_IRUSR) *tmp++ = 'r'; else *tmp++ = '-';
1018         if (inode->i_mode & S_IWUSR) *tmp++ = 'w'; else *tmp++ = '-';
1019         if (inode->i_mode & S_IXUSR) *tmp++ = 'x'; else *tmp++ = '-';
1020         if (inode->i_mode & S_IRGRP) *tmp++ = 'r'; else *tmp++ = '-';
1021         if (inode->i_mode & S_IWGRP) *tmp++ = 'w'; else *tmp++ = '-';
1022         if (inode->i_mode & S_IXGRP) *tmp++ = 'x'; else *tmp++ = '-';
1023         if (inode->i_mode & S_IROTH) *tmp++ = 'r'; else *tmp++ = '-';
1024         if (inode->i_mode & S_IWOTH) *tmp++ = 'w'; else *tmp++ = '-';
1025         if (inode->i_mode & S_IXOTH) *tmp++ = 'x'; else *tmp++ = '-';
1026
1027         *tmp++ = ' ';
1028
1029         size = sprintf(tmp, "%4i %d", inode->i_nlink, inode->i_uid);
1030         tmp += size;
1031
1032         size = 14 - size;
1033         if (size <= 0)
1034                 size = 1;
1035         memset(tmp, ' ', size);
1036         tmp += size;
1037
1038         size = sprintf(tmp, "%d", inode->i_gid);
1039         tmp += size;
1040
1041         size = 9 - size;
1042         if (size <= 0)
1043                 size = 1;
1044         memset(tmp, ' ', size);
1045         tmp += size;
1046
1047         tmp += sprintf(tmp, "%8Li", inode->i_size);
1048         *tmp++ = ' ';
1049
1050         tmp += time_unix2ls(inode->i_mtime.tv_sec, tmp);
1051         *tmp++ = ' ';
1052
1053         memcpy(tmp, d_name, d_len);
1054         tmp += d_len;
1055
1056         if (d_type == DT_LNK) {
1057                 int len = 0, max_len;
1058                 #define ARROW " -> "
1059
1060                 memcpy(tmp, ARROW, sizeof(ARROW)-1);
1061                 tmp += sizeof(ARROW)-1;
1062                 max_len = MAX_OBJECTNAME_LEN-(tmp-string0);
1063                 if (inode->i_op && inode->i_op->readlink) {
1064                         mm_segment_t oldmm;
1065
1066                         oldmm = get_fs(); set_fs(KERNEL_DS);
1067                         set_fs(KERNEL_DS);
1068                         len = inode->i_op->readlink(dentry, tmp, max_len);
1069                         set_fs(oldmm);
1070                 }
1071                 if (len > 0)
1072                         tmp += len;
1073                 else
1074                         Dprintk("hm, readlink() returned %d.\n", len);
1075         }
1076         *tmp++ = '\r';
1077         *tmp++ = '\n';
1078         *tmp = 0;
1079
1080         return tmp;
1081 out_dput:
1082         return NULL;
1083 }
1084
1085 static void ftp_do_ls_onefile (tux_req_t *req, int cachemiss)
1086 {
1087         char string0[MAX_OBJECTNAME_LEN+200], *tmp;
1088
1089         tmp = ftp_print_dir_line(req, string0, req->objectname, req->objectname_len,
1090 DT_REG, req->dentry, req->dentry->d_inode);
1091         if (!tmp) {
1092                 req_err(req);
1093                 add_req_to_workqueue(req);
1094                 return;
1095         }
1096         if (tmp - string0 >= MAX_OBJECTNAME_LEN+200)
1097                 BUG();
1098         __ftp_send_async_message(req, string0, 200, tmp - string0);
1099 }
1100
1101 static void ftp_lookup_listfile (tux_req_t *req, int cachemiss)
1102 {
1103         unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
1104         struct dentry *dentry;
1105         struct vfsmount *mnt = NULL;
1106         int err;
1107
1108         Dprintk("ftp_lookup_listfile(%p, %d, {%s})\n", req, cachemiss, req->objectname);
1109         dentry = tux_lookup(req, req->objectname, flag, &mnt);
1110         if (!dentry || IS_ERR(dentry)) {
1111                 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
1112                         if (cachemiss)
1113                                 TUX_BUG();
1114                         add_tux_atom(req, ftp_lookup_listfile);
1115                         queue_cachemiss(req);
1116                         return;
1117                 }
1118                 goto out_err;
1119         }
1120
1121         if (S_ISDIR(dentry->d_inode->i_mode)) {
1122                 err = permission(dentry->d_inode, MAY_EXEC, NULL);
1123                 if (err) {
1124                         Dprintk("Directory permission error: %d.\n", err);
1125                         goto out_err_put;
1126                 }
1127                 install_req_dentry(req, dentry, mnt);
1128
1129                 add_tux_atom(req, ftp_do_ls_end);
1130                 if (!req->cwd_dentry)
1131                         TUX_BUG();
1132                 add_tux_atom(req, list_directory);
1133         } else {
1134                 install_req_dentry(req, dentry, mnt);
1135
1136                 add_tux_atom(req, ftp_do_ls_end);
1137                 add_tux_atom(req, ftp_do_ls_onefile);
1138         }
1139
1140         add_tux_atom(req, ftp_do_ls_start);
1141         add_tux_atom(req, ftp_wait_syn);
1142         add_tux_atom(req, ftp_flush_req);
1143         ftp_send_async_message(req, WRITE_LIST, 200);
1144         return;
1145
1146 out_err_put:
1147         dput(dentry);
1148         mntput(mnt);
1149 out_err:
1150         ftp_send_async_message(req, BAD_FILENAME, 550);
1151 }
1152
1153 static void ftp_execute_command (tux_req_t *req, int cachemiss)
1154 {
1155         if (!req->parsed_len)
1156                 TUX_BUG();
1157         trunc_headers(req);
1158         req->keep_alive = 1;
1159
1160         switch (req->ftp_command) {
1161
1162 #define ABORTED \
1163         "226 Abort successful.\r\n"
1164
1165         case FTP_COMM_ABOR:
1166         {
1167                 zap_data_socket(req);
1168                 ftp_send_async_message(req, ABORTED, 226);
1169                 break;
1170         }
1171
1172         case FTP_COMM_PWD:
1173         {
1174                 unsigned int str_len;
1175                 char *buf, *path;
1176
1177                 buf = (char *)__get_free_page(GFP_KERNEL);
1178                 if (!buf) {
1179                         req_err(req);
1180                         ftp_send_async_message(req, LIST_ERR_MEM, 200);
1181                         GOTO_ERR;
1182                 }
1183
1184                 if (!req->cwd_dentry) {
1185                         req->cwd_dentry = dget(req->docroot_dentry);
1186                         req->cwd_mnt = mntget(req->docroot_mnt);
1187                 }
1188
1189 // "257 "/" is current directory.\r\n"
1190
1191 #define PART_1 "257 \""
1192 #define PART_1_LEN (sizeof(PART_1)-1)
1193
1194 #define PART_3 "\" is current directory.\r\n"
1195 #define PART_3_LEN sizeof(PART_3)
1196
1197                 path = tux_print_path(req, req->cwd_dentry, req->cwd_mnt,
1198                         buf+PART_1_LEN, PAGE_SIZE - PART_3_LEN - PART_1_LEN);
1199
1200                 if (path < buf + PART_1_LEN)
1201                         BUG();
1202
1203                 memcpy(path - PART_1_LEN, PART_1, PART_1_LEN);
1204                 memcpy(buf + PAGE_SIZE-PART_3_LEN-1, PART_3, PART_3_LEN);
1205                 str_len = buf + PAGE_SIZE-1 - (path - PART_1_LEN) - 1;
1206
1207                 __ftp_send_async_message(req, path - PART_1_LEN, 226, str_len);
1208                 free_page((unsigned long)buf);
1209                 break;
1210         }
1211
1212         case FTP_COMM_CDUP:
1213         {
1214                 memcpy(req->objectname, "..", 3);
1215                 req->objectname_len = 2;
1216                 req->uri_str = req->objectname;
1217                 req->uri_len = req->objectname_len;
1218
1219                 // fall through to CWD:
1220         }
1221         case FTP_COMM_CWD:
1222         {
1223                 ftp_chdir(req, cachemiss);
1224                 break;
1225         }
1226
1227         case FTP_COMM_NLST:
1228         case FTP_COMM_LIST:
1229         {
1230                 if (!req->data_sock) {
1231                         req_err(req);
1232                         ftp_send_async_message(req, LIST_ERR, 200);
1233                         GOTO_ERR;
1234                 }
1235                 if (req->dentry)
1236                         TUX_BUG();
1237                 if (!req->cwd_dentry) {
1238                         req->cwd_dentry = dget(req->docroot_dentry);
1239                         req->cwd_mnt = mntget(req->docroot_mnt);
1240                 }
1241                 if (req->objectname_len)
1242                         ftp_lookup_listfile(req, cachemiss);
1243                 else {
1244                         dget(req->cwd_dentry);
1245                         mntget(req->cwd_mnt);
1246                         install_req_dentry(req, req->cwd_dentry, req->cwd_mnt);
1247                         if (!req->dentry)
1248                                 TUX_BUG();
1249                         add_tux_atom(req, ftp_do_ls_end);
1250                         if (!req->cwd_dentry)
1251                                 TUX_BUG();
1252                         add_tux_atom(req, list_directory);
1253                         add_tux_atom(req, ftp_do_ls_start);
1254                         add_tux_atom(req, ftp_wait_syn);
1255                         add_tux_atom(req, ftp_flush_req);
1256                         ftp_send_async_message(req, WRITE_LIST, 200);
1257                 }
1258                 break;
1259         }
1260
1261         case FTP_COMM_RETR:
1262         {
1263                 if (!req->data_sock) {
1264                         req_err(req);
1265                         ftp_send_async_message(req, RETR_ERR, 200);
1266                         GOTO_ERR;
1267                 }
1268                 ftp_get_file(req, cachemiss);
1269                 break;
1270         }
1271
1272         case FTP_COMM_SIZE:
1273         {
1274                 ftp_get_size(req, cachemiss);
1275                 break;
1276         }
1277
1278         case FTP_COMM_MDTM:
1279         {
1280                 ftp_get_mdtm(req, cachemiss);
1281                 break;
1282         }
1283
1284         case FTP_COMM_PASV:
1285         {
1286                 char buf [36 + 4*3 + 5 + 10];
1287                 struct socket *data_sock;
1288                 struct sockaddr_in addr;
1289                 unsigned int str_len;
1290                 struct tcp_opt *tp;
1291                 u32 local_addr;
1292                 int err;
1293
1294                 if (req->data_sock)
1295                         zap_data_socket(req);
1296                 /*
1297                  * Create FTP data connection to client:
1298                  */
1299                 err = sock_create(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock);
1300                 if (err < 0) {
1301                         Dprintk("sock create err: %d\n", err);
1302                         req_err(req);
1303                         ftp_send_async_message(req, CLOSE, 500);
1304                         GOTO_ERR;
1305                 }
1306                         
1307                 local_addr = inet_sk(req->sock->sk)->rcv_saddr;
1308                 addr.sin_family = AF_INET;
1309                 addr.sin_port = 0;
1310                 addr.sin_addr.s_addr = local_addr;
1311                 Dprintk("client address: (%d,%d,%d,%d).\n", 
1312                         NIPQUAD(inet_sk(req->sock->sk)->daddr));
1313
1314                 data_sock->sk->sk_reuse = 1;
1315                 sock_set_flag(data_sock->sk, SOCK_URGINLINE);
1316                 sock_reset_flag(data_sock->sk, SOCK_LINGER);
1317
1318                 err = data_sock->ops->bind(data_sock,
1319                                 (struct sockaddr*)&addr, sizeof(addr));
1320                 tp = tcp_sk(data_sock->sk);
1321                 tp->nonagle = 2;
1322                 Dprintk("PASV bind() ret: %d.\n", err);
1323                 if (err < 0) {
1324                         req_err(req);
1325                         sock_release(data_sock);
1326                         ftp_send_async_message(req, CLOSE, 500);
1327                         GOTO_ERR;
1328                 }
1329
1330                 tp->ack.pingpong = tux_ack_pingpong;
1331
1332                 if (!tux_keepalive_timeout)
1333                         tp->linger2 = 0;
1334                 else
1335                         tp->linger2 = tux_keepalive_timeout * HZ;
1336
1337                 err = data_sock->ops->listen(data_sock, 1);
1338                 Dprintk("PASV listen() ret: %d\n", err);
1339                 if (err) {
1340                         req_err(req);
1341                         sock_release(data_sock);
1342                         ftp_send_async_message(req, CLOSE, 500);
1343                         GOTO_ERR;
1344                 }
1345                 link_tux_data_socket(req, data_sock);
1346
1347                 Dprintk("FTP PASV listen sock state: %d, sk state: %d\n",
1348                         data_sock->state, data_sock->sk->sk_state);
1349
1350                 str_len = sprintf(buf,
1351                         "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
1352                                 NIPQUAD(local_addr),
1353                                 ntohs(inet_sk(data_sock->sk)->sport) / 256,
1354                                 ntohs(inet_sk(data_sock->sk)->sport) & 255 );
1355                 Dprintk("PASV mess: {%s}\n", buf);
1356
1357                 add_tux_atom(req, ftp_accept_pasv);
1358                 add_tux_atom(req, ftp_flush_req);
1359                 __ftp_send_async_message(req, buf, 227, str_len);
1360                 break;
1361         }
1362
1363         case FTP_COMM_PORT:
1364         {
1365                 struct socket *data_sock;
1366                 struct sockaddr_in addr;
1367                 kernel_cap_t saved_cap;
1368                 u32 local_addr;
1369                 int err;
1370
1371                 /*
1372                  * Create FTP data connection to client:
1373                  */
1374                 err = sock_create(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock);
1375                 if (err < 0) {
1376                         Dprintk("sock create err: %d\n", err);
1377                         req_err(req);
1378                         ftp_send_async_message(req, CLOSE, 500);
1379                         GOTO_ERR;
1380                 }
1381
1382                 local_addr = inet_sk(req->sock->sk)->rcv_saddr;
1383                 addr.sin_family = AF_INET;
1384                 addr.sin_port = htons(20);
1385                 addr.sin_addr.s_addr = local_addr;
1386
1387                 Dprintk("data socket address: (%d,%d,%d,%d).\n",
1388                         NIPQUAD(local_addr));
1389
1390                 data_sock->sk->sk_reuse = 1;
1391                 sock_set_flag(data_sock->sk, SOCK_URGINLINE);
1392                 sock_reset_flag(data_sock->sk, SOCK_LINGER);
1393
1394                 saved_cap = current->cap_effective;
1395                 cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE);
1396                 err = data_sock->ops->bind(data_sock,
1397                                 (struct sockaddr*)&addr, sizeof(addr));
1398                 current->cap_effective = saved_cap;
1399
1400                 Dprintk("ACTIVE bind() ret: %d.\n", err);
1401                 if (err) {
1402                         sock_release(data_sock);
1403                         req_err(req);
1404                         ftp_send_async_message(req, CLOSE, 500);
1405                         GOTO_ERR;
1406                 }
1407                 tcp_sk(data_sock->sk)->nonagle = 2;
1408
1409                 link_tux_data_socket(req, data_sock);
1410
1411                 addr.sin_family = AF_INET;
1412                 addr.sin_port = htons(req->ftp_user_port);
1413                 addr.sin_addr.s_addr = htonl(req->ftp_user_addr);
1414
1415                 err = data_sock->ops->connect(data_sock, (struct sockaddr *) &addr, sizeof(addr), O_RDWR|O_NONBLOCK);
1416                 if (err && (err != -EINPROGRESS)) {
1417                         Dprintk("connect error: %d\n", err);
1418                         zap_data_socket(req);
1419                         req_err(req);
1420                         ftp_send_async_message(req, CLOSE, 500);
1421                         GOTO_ERR;
1422                 }
1423                 Dprintk("FTP data sock state: %d, sk state: %d\n", data_sock->state, data_sock->sk->sk_state);
1424                 ftp_send_async_message(req, PORT_OK, 200);
1425                 break;
1426         }
1427
1428         case FTP_COMM_USER:
1429         {
1430                 if (!strcmp(req->username, "ftp")
1431                          || !strcmp(req->username, "FTP")
1432                          || !strcmp(req->username, "anonymous")
1433                          || !strcmp(req->username, "ANONYMOUS")) {
1434                         unsigned int str_len;
1435                         char login_ok [200];
1436
1437                         if (!tux_ftp_login_message) {
1438                                 ftp_send_async_message(req, LOGIN_OK_PASS, 230);
1439                                 break;
1440                         }
1441                         update_bandwidth(req, 0); /* get current bandwidth */
1442                         if (nr_requests_used() == 1)
1443                                 str_len = sprintf(login_ok, LOGIN_OK_ONE,
1444                                         tux_max_connect, ftp_bandwidth);
1445                         else
1446                                 str_len = sprintf(login_ok, LOGIN_OK,
1447                                         nr_requests_used(), tux_max_connect, ftp_bandwidth);
1448                         __ftp_send_async_message(req, login_ok, 200, str_len);
1449                 } else {
1450                         clear_keepalive(req);
1451                         ftp_send_async_message(req, LOGIN_FORBIDDEN, 530);
1452                 }
1453                 break;
1454         }
1455         case FTP_COMM_PASS:
1456         {
1457                 ftp_send_async_message(req, LOGIN_OK_PASS, 230);
1458                 break;
1459         }
1460         case FTP_COMM_SITE:
1461         {
1462                 ftp_send_async_message(req, SITE, 214);
1463                 break;
1464         }
1465         case FTP_COMM_SYST:
1466         {
1467                 ftp_send_async_message(req, LINUX_SYST, 200);
1468                 break;
1469         }
1470         case FTP_COMM_TYPE:
1471         {
1472                 ftp_send_async_message(req, TYPE_OK, 200);
1473                 break;
1474         }
1475 #define EXTRA_FEATURES "211-Extensions supported:\r\n SIZE\r\n MDTM\r\n211 End\r\n"
1476
1477         case FTP_COMM_FEAT:
1478         {
1479                 ftp_send_async_message(req, EXTRA_FEATURES, 211);
1480                 break;
1481         }
1482         case FTP_COMM_HELP:
1483         case FTP_COMM_CLNT:
1484         case FTP_COMM_NOOP:
1485         {
1486                 ftp_send_async_message(req, COMMAND_OK, 200);
1487                 break;
1488         }
1489         case FTP_COMM_REST:
1490         {
1491                 ftp_send_async_message(req, REST_OK, 200);
1492                 break;
1493         }
1494         case FTP_COMM_QUIT:
1495         {
1496                 clear_keepalive(req);
1497                 ftp_send_async_message(req, BYE, 200);
1498                 break;
1499         }
1500
1501         default:
1502         {
1503                 req->keep_alive = 1;
1504                 ftp_send_async_message(req, CLOSE, 500);
1505                 break;
1506         }
1507         }
1508         return;
1509 error:
1510         Dprintk("rejecting FTP session!\n");
1511         return;
1512 }
1513
1514
1515 static void ftp_timeout (tux_req_t *req, int cachemiss)
1516 {
1517         Dprintk("called ftp_timeout(%p)\n", req);
1518         if (req->error != TUX_ERROR_CONN_TIMEOUT)
1519                 TUX_BUG();
1520         ftp_send_async_message(req, CLOSE_TIMEOUT, 421);
1521 }
1522
1523 static void ftp_close (tux_req_t *req, int cachemiss)
1524 {
1525         Dprintk("called ftp_close(%p)\n", req);
1526         ftp_send_async_message(req, CLOSE, 500);
1527 }
1528
1529 static void ftp_pre_log (tux_req_t *req)
1530 {
1531         if (tux_ftp_log_retr_only && (req->ftp_command != FTP_COMM_RETR))
1532                 req->status = 0;
1533         else
1534                 req->status = req->ftp_command;
1535 }
1536
1537 tux_proto_t tux_proto_ftp = {
1538         defer_accept: 0,
1539         can_redirect: 0,
1540         got_request: ftp_got_request,
1541         parse_message: parse_ftp_message,
1542         illegal_request: ftp_close,
1543         request_timeout: ftp_timeout,
1544         pre_log: ftp_pre_log,
1545         check_req_err: ftp_check_req_err,
1546         print_dir_line: ftp_print_dir_line,
1547         name: "ftp",
1548 };
1549