Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[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 #ifdef 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 inet_connection_sock *icsk1, *icsk2;
891         struct tcp_sock *tp1, *tp2;
892         int err;
893
894         tp1 = tcp_sk(req->data_sock->sk);
895         icsk1 = inet_csk(req->data_sock->sk);
896
897         Dprintk("PASV accept on req %p, accept_queue: %p.\n",
898                         req, &icsk1->icsk_accept_queue);
899         if (req->error || (req->data_sock->sk->sk_state != TCP_LISTEN))
900                 goto error;
901 new_socket:
902         if (reqsk_queue_empty(&icsk1->icsk_accept_queue)) {
903                 spin_lock_irq(&req->ti->work_lock);
904                 add_keepalive_timer(req);
905                 if (test_and_set_bit(0, &req->idle_input))
906                         TUX_BUG();
907                 spin_unlock_irq(&req->ti->work_lock);
908                 if (reqsk_queue_empty(&icsk1->icsk_accept_queue)) {
909                         add_tux_atom(req, ftp_accept_pasv);
910                         return;
911                 }
912                 unidle_req(req);
913         }
914         new_sock = sock_alloc();
915         if (!new_sock)
916                 goto error;
917         sock = req->data_sock;
918         new_sock->type = sock->type;
919         new_sock->ops = sock->ops;
920
921         err = sock->ops->accept(sock, new_sock, O_NONBLOCK);
922         Dprintk("PASV accept() returned %d (state %d).\n", err, new_sock->sk->sk_state);
923         if (err < 0)
924                 goto error;
925         if (new_sock->sk->sk_state != TCP_ESTABLISHED)
926                 goto error;
927         /*
928          * Do not allow other clients to steal the FTP connection!
929          */
930         if (inet_sk(new_sock->sk)->daddr != inet_sk(req->sock->sk)->daddr) {
931                 Dprintk("PASV: ugh, unauthorized connect?\n");
932                 sock_release(new_sock);
933                 new_sock = NULL;
934                 goto new_socket;
935         }
936         /*
937          * Zap the listen socket:
938          */
939         zap_data_socket(req);
940
941         tp2 = tcp_sk(new_sock->sk);
942         icsk2 = inet_csk(new_sock->sk);
943         tp2->nonagle = 2;
944         icsk2->icsk_ack.pingpong = tux_ack_pingpong;
945         new_sock->sk->sk_reuse = 1;
946         sock_set_flag(new_sock->sk, SOCK_URGINLINE);
947         sock_reset_flag(new_sock->sk, SOCK_LINGER);
948
949         link_tux_data_socket(req, new_sock);
950         add_req_to_workqueue(req);
951         return;
952
953 error:
954         if (new_sock)
955                 sock_release(new_sock);
956         req_err(req);
957         zap_data_socket(req);
958         ftp_send_async_message(req, CLOSE, 500);
959 }
960
961 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)
962 {
963         char *string0 = tmp;
964         unsigned int size;
965
966         if (req->ftp_command == FTP_COMM_NLST) {
967                 memcpy(tmp, d_name, d_len);
968                 tmp += d_len;
969                 *tmp++ = '\r';
970                 *tmp++ = '\n';
971                 *tmp = 0;
972                 return tmp;
973         }
974         switch (d_type) {
975                 default:
976                 case DT_UNKNOWN:
977                 case DT_WHT:
978                         if (tux_hide_unreadable)
979                                 goto out_dput;
980                         *tmp++ = '?';
981                         break;
982
983                 case DT_FIFO:
984                         if (tux_hide_unreadable)
985                                 goto out_dput;
986                         *tmp++ = 'p';
987                         break;
988
989                 case DT_CHR:
990                         if (tux_hide_unreadable)
991                                 goto out_dput;
992                         *tmp++ = 'c';
993                         break;
994
995                 case DT_DIR:
996                         *tmp++ = 'd';
997                         break;
998
999                 case DT_BLK:
1000                         if (tux_hide_unreadable)
1001                                 goto out_dput;
1002                         *tmp++ = 'b';
1003                         break;
1004
1005                 case DT_REG:
1006                         *tmp++ = '-';
1007                         break;
1008
1009                 case DT_LNK:
1010                         *tmp++ = 'l';
1011                         break;
1012
1013                 case DT_SOCK:
1014                         if (tux_hide_unreadable)
1015                                 goto out_dput;
1016                         *tmp++ = 's';
1017                         break;
1018         }
1019
1020         if (inode->i_mode & S_IRUSR) *tmp++ = 'r'; else *tmp++ = '-';
1021         if (inode->i_mode & S_IWUSR) *tmp++ = 'w'; else *tmp++ = '-';
1022         if (inode->i_mode & S_IXUSR) *tmp++ = 'x'; else *tmp++ = '-';
1023         if (inode->i_mode & S_IRGRP) *tmp++ = 'r'; else *tmp++ = '-';
1024         if (inode->i_mode & S_IWGRP) *tmp++ = 'w'; else *tmp++ = '-';
1025         if (inode->i_mode & S_IXGRP) *tmp++ = 'x'; else *tmp++ = '-';
1026         if (inode->i_mode & S_IROTH) *tmp++ = 'r'; else *tmp++ = '-';
1027         if (inode->i_mode & S_IWOTH) *tmp++ = 'w'; else *tmp++ = '-';
1028         if (inode->i_mode & S_IXOTH) *tmp++ = 'x'; else *tmp++ = '-';
1029
1030         *tmp++ = ' ';
1031
1032         size = sprintf(tmp, "%4i %d", inode->i_nlink, inode->i_uid);
1033         tmp += size;
1034
1035         size = 14 - size;
1036         if (size <= 0)
1037                 size = 1;
1038         memset(tmp, ' ', size);
1039         tmp += size;
1040
1041         size = sprintf(tmp, "%d", inode->i_gid);
1042         tmp += size;
1043
1044         size = 9 - size;
1045         if (size <= 0)
1046                 size = 1;
1047         memset(tmp, ' ', size);
1048         tmp += size;
1049
1050         tmp += sprintf(tmp, "%8Li", inode->i_size);
1051         *tmp++ = ' ';
1052
1053         tmp += time_unix2ls(inode->i_mtime.tv_sec, tmp);
1054         *tmp++ = ' ';
1055
1056         memcpy(tmp, d_name, d_len);
1057         tmp += d_len;
1058
1059         if (d_type == DT_LNK) {
1060                 int len = 0, max_len;
1061                 #define ARROW " -> "
1062
1063                 memcpy(tmp, ARROW, sizeof(ARROW)-1);
1064                 tmp += sizeof(ARROW)-1;
1065                 max_len = MAX_OBJECTNAME_LEN-(tmp-string0);
1066                 if (inode->i_op && inode->i_op->readlink) {
1067                         mm_segment_t oldmm;
1068
1069                         oldmm = get_fs(); set_fs(KERNEL_DS);
1070                         set_fs(KERNEL_DS);
1071                         len = inode->i_op->readlink(dentry, tmp, max_len);
1072                         set_fs(oldmm);
1073                 }
1074                 if (len > 0)
1075                         tmp += len;
1076                 else
1077                         Dprintk("hm, readlink() returned %d.\n", len);
1078         }
1079         *tmp++ = '\r';
1080         *tmp++ = '\n';
1081         *tmp = 0;
1082
1083         return tmp;
1084 out_dput:
1085         return NULL;
1086 }
1087
1088 static void ftp_do_ls_onefile (tux_req_t *req, int cachemiss)
1089 {
1090         char string0[MAX_OBJECTNAME_LEN+200], *tmp;
1091
1092         tmp = ftp_print_dir_line(req, string0, req->objectname, req->objectname_len,
1093 DT_REG, req->dentry, req->dentry->d_inode);
1094         if (!tmp) {
1095                 req_err(req);
1096                 add_req_to_workqueue(req);
1097                 return;
1098         }
1099         if (tmp - string0 >= MAX_OBJECTNAME_LEN+200)
1100                 BUG();
1101         __ftp_send_async_message(req, string0, 200, tmp - string0);
1102 }
1103
1104 static void ftp_lookup_listfile (tux_req_t *req, int cachemiss)
1105 {
1106         unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
1107         struct dentry *dentry;
1108         struct vfsmount *mnt = NULL;
1109         int err;
1110
1111         Dprintk("ftp_lookup_listfile(%p, %d, {%s})\n", req, cachemiss, req->objectname);
1112         dentry = tux_lookup(req, req->objectname, flag, &mnt);
1113         if (!dentry || IS_ERR(dentry)) {
1114                 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
1115                         if (cachemiss)
1116                                 TUX_BUG();
1117                         add_tux_atom(req, ftp_lookup_listfile);
1118                         queue_cachemiss(req);
1119                         return;
1120                 }
1121                 goto out_err;
1122         }
1123
1124         if (S_ISDIR(dentry->d_inode->i_mode)) {
1125                 err = permission(dentry->d_inode, MAY_EXEC, NULL);
1126                 if (err) {
1127                         Dprintk("Directory permission error: %d.\n", err);
1128                         goto out_err_put;
1129                 }
1130                 install_req_dentry(req, dentry, mnt);
1131
1132                 add_tux_atom(req, ftp_do_ls_end);
1133                 if (!req->cwd_dentry)
1134                         TUX_BUG();
1135                 add_tux_atom(req, list_directory);
1136         } else {
1137                 install_req_dentry(req, dentry, mnt);
1138
1139                 add_tux_atom(req, ftp_do_ls_end);
1140                 add_tux_atom(req, ftp_do_ls_onefile);
1141         }
1142
1143         add_tux_atom(req, ftp_do_ls_start);
1144         add_tux_atom(req, ftp_wait_syn);
1145         add_tux_atom(req, ftp_flush_req);
1146         ftp_send_async_message(req, WRITE_LIST, 200);
1147         return;
1148
1149 out_err_put:
1150         dput(dentry);
1151         mntput(mnt);
1152 out_err:
1153         ftp_send_async_message(req, BAD_FILENAME, 550);
1154 }
1155
1156 static void ftp_execute_command (tux_req_t *req, int cachemiss)
1157 {
1158         if (!req->parsed_len)
1159                 TUX_BUG();
1160         trunc_headers(req);
1161         req->keep_alive = 1;
1162
1163         switch (req->ftp_command) {
1164
1165 #define ABORTED \
1166         "226 Abort successful.\r\n"
1167
1168         case FTP_COMM_ABOR:
1169         {
1170                 zap_data_socket(req);
1171                 ftp_send_async_message(req, ABORTED, 226);
1172                 break;
1173         }
1174
1175         case FTP_COMM_PWD:
1176         {
1177                 unsigned int str_len;
1178                 char *buf, *path;
1179
1180                 buf = (char *)__get_free_page(GFP_KERNEL);
1181                 if (!buf) {
1182                         req_err(req);
1183                         ftp_send_async_message(req, LIST_ERR_MEM, 200);
1184                         GOTO_ERR;
1185                 }
1186
1187                 if (!req->cwd_dentry) {
1188                         req->cwd_dentry = dget(req->docroot_dentry);
1189                         req->cwd_mnt = mntget(req->docroot_mnt);
1190                 }
1191
1192 // "257 "/" is current directory.\r\n"
1193
1194 #define PART_1 "257 \""
1195 #define PART_1_LEN (sizeof(PART_1)-1)
1196
1197 #define PART_3 "\" is current directory.\r\n"
1198 #define PART_3_LEN sizeof(PART_3)
1199
1200                 path = tux_print_path(req, req->cwd_dentry, req->cwd_mnt,
1201                         buf+PART_1_LEN, PAGE_SIZE - PART_3_LEN - PART_1_LEN);
1202
1203                 if (path < buf + PART_1_LEN)
1204                         BUG();
1205
1206                 memcpy(path - PART_1_LEN, PART_1, PART_1_LEN);
1207                 memcpy(buf + PAGE_SIZE-PART_3_LEN-1, PART_3, PART_3_LEN);
1208                 str_len = buf + PAGE_SIZE-1 - (path - PART_1_LEN) - 1;
1209
1210                 __ftp_send_async_message(req, path - PART_1_LEN, 226, str_len);
1211                 free_page((unsigned long)buf);
1212                 break;
1213         }
1214
1215         case FTP_COMM_CDUP:
1216         {
1217                 memcpy(req->objectname, "..", 3);
1218                 req->objectname_len = 2;
1219                 req->uri_str = req->objectname;
1220                 req->uri_len = req->objectname_len;
1221
1222                 // fall through to CWD:
1223         }
1224         case FTP_COMM_CWD:
1225         {
1226                 ftp_chdir(req, cachemiss);
1227                 break;
1228         }
1229
1230         case FTP_COMM_NLST:
1231         case FTP_COMM_LIST:
1232         {
1233                 if (!req->data_sock) {
1234                         req_err(req);
1235                         ftp_send_async_message(req, LIST_ERR, 200);
1236                         GOTO_ERR;
1237                 }
1238                 if (req->dentry)
1239                         TUX_BUG();
1240                 if (!req->cwd_dentry) {
1241                         req->cwd_dentry = dget(req->docroot_dentry);
1242                         req->cwd_mnt = mntget(req->docroot_mnt);
1243                 }
1244                 if (req->objectname_len)
1245                         ftp_lookup_listfile(req, cachemiss);
1246                 else {
1247                         dget(req->cwd_dentry);
1248                         mntget(req->cwd_mnt);
1249                         install_req_dentry(req, req->cwd_dentry, req->cwd_mnt);
1250                         if (!req->dentry)
1251                                 TUX_BUG();
1252                         add_tux_atom(req, ftp_do_ls_end);
1253                         if (!req->cwd_dentry)
1254                                 TUX_BUG();
1255                         add_tux_atom(req, list_directory);
1256                         add_tux_atom(req, ftp_do_ls_start);
1257                         add_tux_atom(req, ftp_wait_syn);
1258                         add_tux_atom(req, ftp_flush_req);
1259                         ftp_send_async_message(req, WRITE_LIST, 200);
1260                 }
1261                 break;
1262         }
1263
1264         case FTP_COMM_RETR:
1265         {
1266                 if (!req->data_sock) {
1267                         req_err(req);
1268                         ftp_send_async_message(req, RETR_ERR, 200);
1269                         GOTO_ERR;
1270                 }
1271                 ftp_get_file(req, cachemiss);
1272                 break;
1273         }
1274
1275         case FTP_COMM_SIZE:
1276         {
1277                 ftp_get_size(req, cachemiss);
1278                 break;
1279         }
1280
1281         case FTP_COMM_MDTM:
1282         {
1283                 ftp_get_mdtm(req, cachemiss);
1284                 break;
1285         }
1286
1287         case FTP_COMM_PASV:
1288         {
1289                 char buf [36 + 4*3 + 5 + 10];
1290                 struct socket *data_sock;
1291                 struct sockaddr_in addr;
1292                 unsigned int str_len;
1293                 struct tcp_sock *tp;
1294                 struct inet_connection_sock *icsk;
1295                 u32 local_addr;
1296                 int err;
1297
1298                 if (req->data_sock)
1299                         zap_data_socket(req);
1300                 /*
1301                  * Create FTP data connection to client:
1302                  */
1303                 err = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock);
1304                 if (err < 0) {
1305                         Dprintk("sock create err: %d\n", err);
1306                         req_err(req);
1307                         ftp_send_async_message(req, CLOSE, 500);
1308                         GOTO_ERR;
1309                 }
1310
1311                 local_addr = inet_sk(req->sock->sk)->rcv_saddr;
1312                 addr.sin_family = AF_INET;
1313                 addr.sin_port = 0;
1314                 addr.sin_addr.s_addr = local_addr;
1315                 Dprintk("client address: (%d,%d,%d,%d).\n",
1316                         NIPQUAD(inet_sk(req->sock->sk)->daddr));
1317
1318                 data_sock->sk->sk_reuse = 1;
1319                 sock_set_flag(data_sock->sk, SOCK_URGINLINE);
1320                 sock_reset_flag(data_sock->sk, SOCK_LINGER);
1321
1322                 err = data_sock->ops->bind(data_sock,
1323                                 (struct sockaddr*)&addr, sizeof(addr));
1324                 tp = tcp_sk(data_sock->sk);
1325                 icsk = inet_csk(data_sock->sk);
1326
1327                 tp->nonagle = 2;
1328                 Dprintk("PASV bind() ret: %d.\n", err);
1329                 if (err < 0) {
1330                         req_err(req);
1331                         sock_release(data_sock);
1332                         ftp_send_async_message(req, CLOSE, 500);
1333                         GOTO_ERR;
1334                 }
1335
1336                 icsk->icsk_ack.pingpong = tux_ack_pingpong;
1337
1338                 if (!tux_keepalive_timeout)
1339                         tp->linger2 = 0;
1340                 else
1341                         tp->linger2 = tux_keepalive_timeout * HZ;
1342
1343                 err = data_sock->ops->listen(data_sock, 1);
1344                 Dprintk("PASV listen() ret: %d\n", err);
1345                 if (err) {
1346                         req_err(req);
1347                         sock_release(data_sock);
1348                         ftp_send_async_message(req, CLOSE, 500);
1349                         GOTO_ERR;
1350                 }
1351                 link_tux_data_socket(req, data_sock);
1352
1353                 Dprintk("FTP PASV listen sock state: %d, sk state: %d\n",
1354                         data_sock->state, data_sock->sk->sk_state);
1355
1356                 str_len = sprintf(buf,
1357                         "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
1358                                 NIPQUAD(local_addr),
1359                                 ntohs(inet_sk(data_sock->sk)->sport) / 256,
1360                                 ntohs(inet_sk(data_sock->sk)->sport) & 255 );
1361                 Dprintk("PASV mess: {%s}\n", buf);
1362
1363                 add_tux_atom(req, ftp_accept_pasv);
1364                 add_tux_atom(req, ftp_flush_req);
1365                 __ftp_send_async_message(req, buf, 227, str_len);
1366                 break;
1367         }
1368
1369         case FTP_COMM_PORT:
1370         {
1371                 struct socket *data_sock;
1372                 struct sockaddr_in addr;
1373                 kernel_cap_t saved_cap;
1374                 u32 local_addr;
1375                 int err;
1376
1377                 /*
1378                  * Create FTP data connection to client:
1379                  */
1380                 err = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock);
1381                 if (err < 0) {
1382                         Dprintk("sock create err: %d\n", err);
1383                         req_err(req);
1384                         ftp_send_async_message(req, CLOSE, 500);
1385                         GOTO_ERR;
1386                 }
1387
1388                 local_addr = inet_sk(req->sock->sk)->rcv_saddr;
1389                 addr.sin_family = AF_INET;
1390                 addr.sin_port = htons(20);
1391                 addr.sin_addr.s_addr = local_addr;
1392
1393                 Dprintk("data socket address: (%d,%d,%d,%d).\n",
1394                         NIPQUAD(local_addr));
1395
1396                 data_sock->sk->sk_reuse = 1;
1397                 sock_set_flag(data_sock->sk, SOCK_URGINLINE);
1398                 sock_reset_flag(data_sock->sk, SOCK_LINGER);
1399
1400                 saved_cap = current->cap_effective;
1401                 cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE);
1402                 err = data_sock->ops->bind(data_sock,
1403                                 (struct sockaddr*)&addr, sizeof(addr));
1404                 current->cap_effective = saved_cap;
1405
1406                 Dprintk("ACTIVE bind() ret: %d.\n", err);
1407                 if (err) {
1408                         sock_release(data_sock);
1409                         req_err(req);
1410                         ftp_send_async_message(req, CLOSE, 500);
1411                         GOTO_ERR;
1412                 }
1413                 tcp_sk(data_sock->sk)->nonagle = 2;
1414
1415                 link_tux_data_socket(req, data_sock);
1416
1417                 addr.sin_family = AF_INET;
1418                 addr.sin_port = htons(req->ftp_user_port);
1419                 addr.sin_addr.s_addr = htonl(req->ftp_user_addr);
1420
1421                 err = data_sock->ops->connect(data_sock, (struct sockaddr *) &addr, sizeof(addr), O_RDWR|O_NONBLOCK);
1422                 if (err && (err != -EINPROGRESS)) {
1423                         Dprintk("connect error: %d\n", err);
1424                         zap_data_socket(req);
1425                         req_err(req);
1426                         ftp_send_async_message(req, CLOSE, 500);
1427                         GOTO_ERR;
1428                 }
1429                 Dprintk("FTP data sock state: %d, sk state: %d\n", data_sock->state, data_sock->sk->sk_state);
1430                 ftp_send_async_message(req, PORT_OK, 200);
1431                 break;
1432         }
1433
1434         case FTP_COMM_USER:
1435         {
1436                 if (!strcmp(req->username, "ftp")
1437                          || !strcmp(req->username, "FTP")
1438                          || !strcmp(req->username, "anonymous")
1439                          || !strcmp(req->username, "ANONYMOUS")) {
1440                         unsigned int str_len;
1441                         char login_ok [200];
1442
1443                         if (!tux_ftp_login_message) {
1444                                 ftp_send_async_message(req, LOGIN_OK_PASS, 230);
1445                                 break;
1446                         }
1447                         update_bandwidth(req, 0); /* get current bandwidth */
1448                         if (nr_requests_used() == 1)
1449                                 str_len = sprintf(login_ok, LOGIN_OK_ONE,
1450                                         tux_max_connect, ftp_bandwidth);
1451                         else
1452                                 str_len = sprintf(login_ok, LOGIN_OK,
1453                                         nr_requests_used(), tux_max_connect, ftp_bandwidth);
1454                         __ftp_send_async_message(req, login_ok, 200, str_len);
1455                 } else {
1456                         clear_keepalive(req);
1457                         ftp_send_async_message(req, LOGIN_FORBIDDEN, 530);
1458                 }
1459                 break;
1460         }
1461         case FTP_COMM_PASS:
1462         {
1463                 ftp_send_async_message(req, LOGIN_OK_PASS, 230);
1464                 break;
1465         }
1466         case FTP_COMM_SITE:
1467         {
1468                 ftp_send_async_message(req, SITE, 214);
1469                 break;
1470         }
1471         case FTP_COMM_SYST:
1472         {
1473                 ftp_send_async_message(req, LINUX_SYST, 200);
1474                 break;
1475         }
1476         case FTP_COMM_TYPE:
1477         {
1478                 ftp_send_async_message(req, TYPE_OK, 200);
1479                 break;
1480         }
1481 #define EXTRA_FEATURES "211-Extensions supported:\r\n SIZE\r\n MDTM\r\n211 End\r\n"
1482
1483         case FTP_COMM_FEAT:
1484         {
1485                 ftp_send_async_message(req, EXTRA_FEATURES, 211);
1486                 break;
1487         }
1488         case FTP_COMM_HELP:
1489         case FTP_COMM_CLNT:
1490         case FTP_COMM_NOOP:
1491         {
1492                 ftp_send_async_message(req, COMMAND_OK, 200);
1493                 break;
1494         }
1495         case FTP_COMM_REST:
1496         {
1497                 ftp_send_async_message(req, REST_OK, 200);
1498                 break;
1499         }
1500         case FTP_COMM_QUIT:
1501         {
1502                 clear_keepalive(req);
1503                 ftp_send_async_message(req, BYE, 200);
1504                 break;
1505         }
1506
1507         default:
1508         {
1509                 req->keep_alive = 1;
1510                 ftp_send_async_message(req, CLOSE, 500);
1511                 break;
1512         }
1513         }
1514         return;
1515 error:
1516         Dprintk("rejecting FTP session!\n");
1517         return;
1518 }
1519
1520
1521 static void ftp_timeout (tux_req_t *req, int cachemiss)
1522 {
1523         Dprintk("called ftp_timeout(%p)\n", req);
1524         if (req->error != TUX_ERROR_CONN_TIMEOUT)
1525                 TUX_BUG();
1526         ftp_send_async_message(req, CLOSE_TIMEOUT, 421);
1527 }
1528
1529 static void ftp_close (tux_req_t *req, int cachemiss)
1530 {
1531         Dprintk("called ftp_close(%p)\n", req);
1532         ftp_send_async_message(req, CLOSE, 500);
1533 }
1534
1535 static void ftp_pre_log (tux_req_t *req)
1536 {
1537         if (tux_ftp_log_retr_only && (req->ftp_command != FTP_COMM_RETR))
1538                 req->status = 0;
1539         else
1540                 req->status = req->ftp_command;
1541 }
1542
1543 tux_proto_t tux_proto_ftp = {
1544         .defer_accept = 0,
1545         .can_redirect = 0,
1546         .got_request = ftp_got_request,
1547         .parse_message = parse_ftp_message,
1548         .illegal_request = ftp_close,
1549         .request_timeout = ftp_timeout,
1550         .pre_log = ftp_pre_log,
1551         .check_req_err = ftp_check_req_err,
1552         .print_dir_line = ftp_print_dir_line,
1553         .name = "ftp",
1554 };
1555