2 * TUX - Integrated Application Protocols Layer and Object Cache
4 * Copyright (C) 2000, 2001, Ingo Molnar <mingo@redhat.com>
6 * ftp_proto.c: FTP application protocol support
9 #define __KERNEL_SYSCALLS__
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)
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.
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.
27 ****************************************************************/
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"
57 unsigned long last_measurement;
58 unsigned int ftp_bytes_sent;
59 unsigned int ftp_bandwidth;
61 static void __update_bandwidth (tux_req_t *req, unsigned int bytes)
64 * Bandwidth measurement. Not completely accurate,
65 * but it's good enough and lightweight enough.
67 if (jiffies >= last_measurement + INTERVAL*HZ) {
68 ftp_bandwidth = (ftp_bytes_sent + 1023)/INTERVAL/1024;
70 last_measurement = jiffies;
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);
78 #define update_bandwidth(req,bytes) \
80 if (unlikely(tux_ftp_login_message)) \
81 __update_bandwidth(req, bytes); \
84 static inline void __ftp_send_async_message (tux_req_t *req,
85 const char *message, int status, unsigned int size)
87 update_bandwidth(req, size);
88 __send_async_message(req, message, status, size, 1);
91 #define ftp_send_async_message(req,str,status) \
92 __ftp_send_async_message(req,str,status,sizeof(str)-1)
95 static void ftp_flush_req (tux_req_t *req, int cachemiss)
97 tux_push_pending(req->sock->sk);
98 add_req_to_workqueue(req);
101 static void ftp_execute_command (tux_req_t *req, int cachemiss);
103 static void ftp_lookup_vhost (tux_req_t *req, int cachemiss)
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];
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);
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);
120 dentry = __tux_lookup(req, ip, &base, &mnt);
122 Dprintk("looked up dentry %p.\n", dentry);
123 if (dentry && !IS_ERR(dentry) && !dentry->d_inode)
126 if (!dentry || IS_ERR(dentry)) {
127 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
128 add_tux_atom(req, ftp_lookup_vhost);
129 queue_cachemiss(req);
135 req->docroot_dentry = dentry;
136 req->docroot_mnt = mnt;
138 add_tux_atom(req, ftp_execute_command);
139 add_req_to_workqueue(req);
153 add_req_to_workqueue(req);
156 static void ftp_got_request (tux_req_t *req)
158 add_tux_atom(req, parse_request);
159 add_tux_atom(req, ftp_flush_req);
160 ftp_send_async_message(req, HELLO, 220);
163 #define GOTO_ERR { TDprintk("FTP protocol error at: %s:%d\n", \
164 __FILE__, __LINE__); goto error; }
166 static void zap_data_socket (tux_req_t *req)
170 Dprintk("zapping req %p's data socket %p.\n", req, req->data_sock);
172 unlink_tux_data_socket(req);
173 sock_release(req->data_sock);
174 req->data_sock = NULL;
177 static int parse_ftp_message (tux_req_t *req, const int total_len)
179 int comm, comm1 = 0, comm2 = 0, comm3 = 0, comm4 = 0;
181 const char *mess, *curr;
183 curr = mess = req->headers;
185 Dprintk("FTP parser got %d bytes: --->{%s}<---\n", total_len, curr);
188 for (i = 0; i < total_len; i++, curr++) {
191 if (!(*curr == '\r') || !(*(curr+1) == '\n'))
196 Dprintk("Newline pos: %d\n", newline_pos);
197 if (newline_pos == -1) {
198 Dprintk("incomplete mess on req %p!\n", req);
204 #define toup(c) ((((c) >= 'a') && ((c) <= 'z')) ? ((c) + 'A' - 'a') : (c))
206 #define STRING_VAL(c1,c2,c3,c4) \
207 (toup(c1) + (toup(c2) << 8) + (toup(c3) << 16) + (toup(c4) << 24))
209 #define STRING_VAL_STR(str) \
210 STRING_VAL(str[0], str[1], str[2], str[3])
212 Dprintk("string val (%c%c%c%c): %08x\n",
213 mess[0], mess[1], mess[2], mess[3],
214 STRING_VAL_STR(mess));
216 #define PARSE_FTP_COMM(c1,c2,c3,c4,name,num) \
217 if (STRING_VAL_STR(mess) == STRING_VAL(c1,c2,c3,c4)) \
219 Dprintk("parsed "#name".\n"); \
220 comm##num = FTP_COMM_##name; \
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);
245 comm = comm1 | comm2 | comm3 | comm4;
248 if (newline_pos != 4)
250 req->ftp_command = comm;
254 switch (STRING_VAL(mess[0], mess[1], mess[2], mess[3])) {
256 #define PARSE_FTP_COMM_3CHAR(c1,c2,c3,name) \
257 case STRING_VAL(c1,c2,c3,'\r'): \
259 Dprintk("parsed "#name".\n"); \
260 req->ftp_command = FTP_COMM_##name; \
261 if (newline_pos != 3) \
265 #define PARSE_FTP_3CHAR_COMM_IGNORE(c1,c2,c3,name) \
266 case STRING_VAL(c1,c2,c3,' '): \
268 Dprintk("parsed "#name".\n"); \
269 req->ftp_command = FTP_COMM_##name; \
272 #define PARSE_FTP_COMM_IGNORE(c1,c2,c3,c4,name) \
273 case STRING_VAL(c1,c2,c3,c4): \
275 Dprintk("parsed "#name".\n"); \
276 req->ftp_command = FTP_COMM_##name; \
279 #define PARSE_FTP_3CHAR_COMM_1_FIELD(c1,c2,c3,name,field,field_len,max) \
280 case STRING_VAL(c1,c2,c3,' '): \
282 Dprintk("parsed "#name".\n"); \
283 req->ftp_command = FTP_COMM_##name; \
284 if (newline_pos == 4) \
286 if (newline_pos >= 5) { \
288 if (*curr++ != ' ') \
290 *(field_len) = newline_pos-4; \
291 if (*(field_len) >= max) \
293 memcpy(field, curr, *(field_len)); \
294 (field)[*(field_len)] = 0; \
298 #define PARSE_FTP_COMM_1_FIELD(c1,c2,c3,c4,name,field,field_len,max) \
299 case STRING_VAL(c1,c2,c3,c4): \
301 Dprintk("parsed "#name".\n"); \
302 req->ftp_command = FTP_COMM_##name; \
303 if (newline_pos < 4) \
305 if (newline_pos == 4) \
309 if (*curr++ != ' ') \
311 *(field_len) = newline_pos-5; \
312 if (*(field_len) >= max) \
314 memcpy(field, curr, *(field_len)); \
315 (field)[*(field_len)] = 0; \
319 PARSE_FTP_COMM_1_FIELD('U','S','E','R', USER,
320 req->username, &req->username_len,
322 if (!req->username_len)
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,
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)
343 req->uri_str = req->objectname;
344 req->uri_len = req->objectname_len;
347 PARSE_FTP_COMM_3CHAR('P','W','D', PWD); break;
351 unsigned int type_len;
353 PARSE_FTP_COMM_1_FIELD('T','Y','P','E', TYPE,
357 if ((type[0] != 'I') && (type[0] != 'A'))
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;
369 req->uri_str = req->objectname;
370 req->uri_len = req->objectname_len;
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;
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;
391 PARSE_FTP_COMM_IGNORE('M','O','D','E', MODE);
394 PARSE_FTP_COMM_IGNORE('S','T','A','T', STAT);
397 PARSE_FTP_COMM_IGNORE('S','I','T','E', SITE);
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;
407 if (req->objectname_len) {
408 req->uri_str = req->objectname;
409 req->uri_len = req->objectname_len;
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;
420 if (req->objectname_len) {
421 req->uri_str = req->objectname;
422 req->uri_len = req->objectname_len;
426 PARSE_FTP_COMM_IGNORE('H','E','L','P', HELP);
429 PARSE_FTP_COMM_IGNORE('C','L','N','T', CLNT);
432 #define IS_NUM(n) (((n) >= '0') && ((n) <= '9'))
434 #define GET_DIGIT(curr,n) \
435 n += (*curr) - '0'; \
437 if (IS_NUM(*curr)) { \
440 #define PARSE_PORTNUM(curr,n) \
442 Dprintk("PORT NUM parser:--->{%s}<---\n", curr);\
443 if (!IS_NUM(*curr)) \
452 Dprintk("PORT NUM parser:--->{%s}<---\n", curr);\
453 Dprintk("PORT NUM parser parsed %d.\n", n); \
456 #define PARSE_NUM(curr,n) \
458 Dprintk("NUM parser:--->{%s}<---\n", curr); \
459 if (!IS_NUM(*curr)) \
473 Dprintk("NUM parser:--->{%s}<---\n", curr); \
474 Dprintk("NUM parser parsed %d.\n", n); \
477 case STRING_VAL('P','O','R','T'):
479 unsigned int h1, h2, h3, h4, p1, p2;
481 zap_data_socket(req);
483 * Minimum size: "PORT 0,0,0,0,0,0", 16 bytes.
485 if (newline_pos < 16)
487 Dprintk("parsed PORT.\n");
493 PARSE_PORTNUM(curr,h1);
496 PARSE_PORTNUM(curr,h2);
499 PARSE_PORTNUM(curr,h3);
502 PARSE_PORTNUM(curr,h4);
505 PARSE_PORTNUM(curr,p1);
508 PARSE_PORTNUM(curr,p2);
509 if (curr-mess != newline_pos)
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);
520 * Do not allow redirection of connections, and do
521 * not allow reserved ports to be accessed.
523 if (inet_sk(req->sock->sk)->daddr != htonl(req->ftp_user_addr))
525 if (req->ftp_user_port < 1024)
529 case STRING_VAL('R','E','S','T'):
534 * Minimum size: "REST 0", 6 bytes.
538 Dprintk("parsed REST.\n");
542 PARSE_NUM(curr,offset);
543 if (curr-mess != newline_pos)
545 req->ftp_command = FTP_COMM_REST;
546 req->ftp_offset_start = offset;
547 Dprintk("FTP REST got: %d bytes offset.\n", offset);
552 req->ftp_command = FTP_COMM_NONE;
557 req->parsed_len = newline_pos + 2;
559 req->virtual = tux_ftp_virtual_server;
561 add_tux_atom(req, ftp_lookup_vhost);
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);
568 return req->parsed_len;
570 clear_keepalive(req);
571 TDprintk("rejecting FTP session!\n");
572 TDprintk("mess :--->{%s}<---\n", mess);
573 TDprintk("mess left:--->{%s}<---\n", curr);
578 static void ftp_wait_close (tux_req_t *req, int cachemiss);
579 static void ftp_wait_syn (tux_req_t *req, int cachemiss);
581 static int ftp_check_req_err (tux_req_t *req, int cachemiss)
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;
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;
593 if ((state <= TCP_SYN_RECV) && !err) {
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);
603 req->bytes_expected = 0;
607 req->in_file.f_pos = 0;
608 TDprintk("zapping, data sock state: %d (err: %d, urg: %d)\n",
611 * We are in the middle of a file transfer,
612 * zap it immediately:
614 req->error = TUX_ERROR_CONN_CLOSE;
615 zap_request(req, cachemiss);
619 void ftp_send_file (tux_req_t *req, int cachemiss)
623 SET_TIMESTAMP(req->output_timestamp);
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;
631 add_tux_atom(req, ftp_send_file);
635 add_tux_atom(req, ftp_send_file);
636 if (add_output_space_event(req, req->data_sock)) {
642 add_tux_atom(req, ftp_send_file);
643 queue_cachemiss(req);
648 req->in_file.f_pos = 0;
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);
656 Dprintk("FTP send file req %p finished!\n", req);
657 zap_data_socket(req);
658 add_tux_atom(req, ftp_flush_req);
660 ftp_send_async_message(req, BAD_FILENAME, 200);
662 ftp_send_async_message(req, WRITE_DONE, 200);
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))
672 static void ftp_wait_syn (tux_req_t *req, int cachemiss)
674 Dprintk("ftp_wait_syn in: data socket state %d.\n", req->data_sock->state);
676 spin_lock_irq(&req->ti->work_lock);
677 add_keepalive_timer(req);
678 if (test_and_set_bit(0, &req->idle_input))
680 spin_unlock_irq(&req->ti->work_lock);
682 add_tux_atom(req, ftp_wait_syn);
687 Dprintk("ftp_wait_syn out: data socket state %d.\n", req->data_sock->state);
688 add_req_to_workqueue(req);
691 static void ftp_wait_close (tux_req_t *req, int cachemiss)
693 struct sock *sk = req->data_sock->sk;
695 Dprintk("ftp_wait_close: data socket state %d.\n", sk->sk_state);
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))
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);
709 zap_data_socket(req);
710 add_tux_atom(req, ftp_flush_req);
712 ftp_send_async_message(req, BAD_FILENAME, 200);
714 ftp_send_async_message(req, WRITE_DONE, 200);
717 void ftp_get_size (tux_req_t *req, int cachemiss)
723 missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC);
724 if (!missed && !req->dentry) {
725 ftp_send_async_message(req, BAD_FILENAME, 200);
731 add_tux_atom(req, ftp_get_size);
732 queue_cachemiss(req);
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);
741 void ftp_get_mdtm (tux_req_t *req, int cachemiss)
743 unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
744 struct dentry *dentry;
745 struct vfsmount *mnt = NULL;
750 dentry = tux_lookup(req, req->objectname, flag, &mnt);
751 if (!dentry || IS_ERR(dentry)) {
752 if (PTR_ERR(dentry) == -EWOULDBLOCKIO) {
755 add_tux_atom(req, ftp_get_mdtm);
756 queue_cachemiss(req);
761 err = permission(dentry->d_inode, MAY_READ, NULL);
765 req->in_file.f_pos = 0;
766 len = mdtm_time (file_mdtm, dentry->d_inode->i_mtime.tv_sec);
769 __ftp_send_async_message(req, file_mdtm, 200, len);
776 ftp_send_async_message(req, BAD_FILENAME, 550);
779 static void ftp_get_file (tux_req_t *req, int cachemiss)
784 missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC);
785 if (!missed && !req->dentry) {
786 ftp_send_async_message(req, BAD_FILENAME, 200);
792 add_tux_atom(req, ftp_get_file);
793 queue_cachemiss(req);
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;
804 req->ftp_offset_start = 0;
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);
815 static void __exchange_sockets (tux_req_t *req)
819 tmp = req->data_sock;
820 req->data_sock = req->sock;
823 req->in_file.f_pos = 0;
826 static void ftp_do_ls_start (tux_req_t *req, int cachemiss)
828 Dprintk("ftp_do_ls_start(%p, %d).\n", req, cachemiss);
829 if (!req->cwd_dentry)
831 __exchange_sockets(req);
832 queue_cachemiss(req);
835 static void ftp_do_ls_end (tux_req_t *req, int cachemiss)
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);
845 zap_data_socket(req);
846 add_tux_atom(req, ftp_flush_req);
848 ftp_send_async_message(req, BAD_FILENAME, 200);
850 ftp_send_async_message(req, WRITE_DONE, 200);
853 static void ftp_chdir (tux_req_t *req, int cachemiss)
855 unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
856 struct dentry *dentry;
857 struct vfsmount *mnt = NULL;
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) {
866 add_tux_atom(req, ftp_chdir);
867 queue_cachemiss(req);
872 err = permission(dentry->d_inode, MAY_EXEC, NULL);
875 req->cwd_dentry = dentry;
877 ftp_send_async_message(req, GOOD_DIR, 200);
884 ftp_send_async_message(req, BAD_FILENAME, 550);
887 void ftp_accept_pasv (tux_req_t *req, int cachemiss)
889 struct socket *sock, *new_sock = NULL;
890 struct tcp_opt *tp1, *tp2;
893 tp1 = tcp_sk(req->data_sock->sk);
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))
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))
905 spin_unlock_irq(&req->ti->work_lock);
906 if (!tp1->accept_queue) {
907 add_tux_atom(req, ftp_accept_pasv);
912 new_sock = sock_alloc();
915 sock = req->data_sock;
916 new_sock->type = sock->type;
917 new_sock->ops = sock->ops;
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);
923 if (new_sock->sk->sk_state != TCP_ESTABLISHED)
926 * Do not allow other clients to steal the FTP connection!
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);
935 * Zap the listen socket:
937 zap_data_socket(req);
939 tp2 = tcp_sk(new_sock->sk);
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);
946 link_tux_data_socket(req, new_sock);
947 add_req_to_workqueue(req);
952 sock_release(new_sock);
954 zap_data_socket(req);
955 ftp_send_async_message(req, CLOSE, 500);
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)
963 if (req->ftp_command == FTP_COMM_NLST) {
964 memcpy(tmp, d_name, d_len);
975 if (tux_hide_unreadable)
981 if (tux_hide_unreadable)
987 if (tux_hide_unreadable)
997 if (tux_hide_unreadable)
1011 if (tux_hide_unreadable)
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++ = '-';
1029 size = sprintf(tmp, "%4i %d", inode->i_nlink, inode->i_uid);
1035 memset(tmp, ' ', size);
1038 size = sprintf(tmp, "%d", inode->i_gid);
1044 memset(tmp, ' ', size);
1047 tmp += sprintf(tmp, "%8Li", inode->i_size);
1050 tmp += time_unix2ls(inode->i_mtime.tv_sec, tmp);
1053 memcpy(tmp, d_name, d_len);
1056 if (d_type == DT_LNK) {
1057 int len = 0, max_len;
1058 #define ARROW " -> "
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) {
1066 oldmm = get_fs(); set_fs(KERNEL_DS);
1068 len = inode->i_op->readlink(dentry, tmp, max_len);
1074 Dprintk("hm, readlink() returned %d.\n", len);
1085 static void ftp_do_ls_onefile (tux_req_t *req, int cachemiss)
1087 char string0[MAX_OBJECTNAME_LEN+200], *tmp;
1089 tmp = ftp_print_dir_line(req, string0, req->objectname, req->objectname_len,
1090 DT_REG, req->dentry, req->dentry->d_inode);
1093 add_req_to_workqueue(req);
1096 if (tmp - string0 >= MAX_OBJECTNAME_LEN+200)
1098 __ftp_send_async_message(req, string0, 200, tmp - string0);
1101 static void ftp_lookup_listfile (tux_req_t *req, int cachemiss)
1103 unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC;
1104 struct dentry *dentry;
1105 struct vfsmount *mnt = NULL;
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) {
1114 add_tux_atom(req, ftp_lookup_listfile);
1115 queue_cachemiss(req);
1121 if (S_ISDIR(dentry->d_inode->i_mode)) {
1122 err = permission(dentry->d_inode, MAY_EXEC, NULL);
1124 Dprintk("Directory permission error: %d.\n", err);
1127 install_req_dentry(req, dentry, mnt);
1129 add_tux_atom(req, ftp_do_ls_end);
1130 if (!req->cwd_dentry)
1132 add_tux_atom(req, list_directory);
1134 install_req_dentry(req, dentry, mnt);
1136 add_tux_atom(req, ftp_do_ls_end);
1137 add_tux_atom(req, ftp_do_ls_onefile);
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);
1150 ftp_send_async_message(req, BAD_FILENAME, 550);
1153 static void ftp_execute_command (tux_req_t *req, int cachemiss)
1155 if (!req->parsed_len)
1158 req->keep_alive = 1;
1160 switch (req->ftp_command) {
1163 "226 Abort successful.\r\n"
1167 zap_data_socket(req);
1168 ftp_send_async_message(req, ABORTED, 226);
1174 unsigned int str_len;
1177 buf = (char *)__get_free_page(GFP_KERNEL);
1180 ftp_send_async_message(req, LIST_ERR_MEM, 200);
1184 if (!req->cwd_dentry) {
1185 req->cwd_dentry = dget(req->docroot_dentry);
1186 req->cwd_mnt = mntget(req->docroot_mnt);
1189 // "257 "/" is current directory.\r\n"
1191 #define PART_1 "257 \""
1192 #define PART_1_LEN (sizeof(PART_1)-1)
1194 #define PART_3 "\" is current directory.\r\n"
1195 #define PART_3_LEN sizeof(PART_3)
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);
1200 if (path < buf + PART_1_LEN)
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;
1207 __ftp_send_async_message(req, path - PART_1_LEN, 226, str_len);
1208 free_page((unsigned long)buf);
1214 memcpy(req->objectname, "..", 3);
1215 req->objectname_len = 2;
1216 req->uri_str = req->objectname;
1217 req->uri_len = req->objectname_len;
1219 // fall through to CWD:
1223 ftp_chdir(req, cachemiss);
1230 if (!req->data_sock) {
1232 ftp_send_async_message(req, LIST_ERR, 200);
1237 if (!req->cwd_dentry) {
1238 req->cwd_dentry = dget(req->docroot_dentry);
1239 req->cwd_mnt = mntget(req->docroot_mnt);
1241 if (req->objectname_len)
1242 ftp_lookup_listfile(req, cachemiss);
1244 dget(req->cwd_dentry);
1245 mntget(req->cwd_mnt);
1246 install_req_dentry(req, req->cwd_dentry, req->cwd_mnt);
1249 add_tux_atom(req, ftp_do_ls_end);
1250 if (!req->cwd_dentry)
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);
1263 if (!req->data_sock) {
1265 ftp_send_async_message(req, RETR_ERR, 200);
1268 ftp_get_file(req, cachemiss);
1274 ftp_get_size(req, cachemiss);
1280 ftp_get_mdtm(req, cachemiss);
1286 char buf [36 + 4*3 + 5 + 10];
1287 struct socket *data_sock;
1288 struct sockaddr_in addr;
1289 unsigned int str_len;
1295 zap_data_socket(req);
1297 * Create FTP data connection to client:
1299 err = sock_create(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock);
1301 Dprintk("sock create err: %d\n", err);
1303 ftp_send_async_message(req, CLOSE, 500);
1307 local_addr = inet_sk(req->sock->sk)->rcv_saddr;
1308 addr.sin_family = AF_INET;
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));
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);
1318 err = data_sock->ops->bind(data_sock,
1319 (struct sockaddr*)&addr, sizeof(addr));
1320 tp = tcp_sk(data_sock->sk);
1322 Dprintk("PASV bind() ret: %d.\n", err);
1325 sock_release(data_sock);
1326 ftp_send_async_message(req, CLOSE, 500);
1330 tp->ack.pingpong = tux_ack_pingpong;
1332 if (!tux_keepalive_timeout)
1335 tp->linger2 = tux_keepalive_timeout * HZ;
1337 err = data_sock->ops->listen(data_sock, 1);
1338 Dprintk("PASV listen() ret: %d\n", err);
1341 sock_release(data_sock);
1342 ftp_send_async_message(req, CLOSE, 500);
1345 link_tux_data_socket(req, data_sock);
1347 Dprintk("FTP PASV listen sock state: %d, sk state: %d\n",
1348 data_sock->state, data_sock->sk->sk_state);
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);
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);
1365 struct socket *data_sock;
1366 struct sockaddr_in addr;
1367 kernel_cap_t saved_cap;
1372 * Create FTP data connection to client:
1374 err = sock_create(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock);
1376 Dprintk("sock create err: %d\n", err);
1378 ftp_send_async_message(req, CLOSE, 500);
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;
1387 Dprintk("data socket address: (%d,%d,%d,%d).\n",
1388 NIPQUAD(local_addr));
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);
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;
1400 Dprintk("ACTIVE bind() ret: %d.\n", err);
1402 sock_release(data_sock);
1404 ftp_send_async_message(req, CLOSE, 500);
1407 tcp_sk(data_sock->sk)->nonagle = 2;
1409 link_tux_data_socket(req, data_sock);
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);
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);
1420 ftp_send_async_message(req, CLOSE, 500);
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);
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];
1437 if (!tux_ftp_login_message) {
1438 ftp_send_async_message(req, LOGIN_OK_PASS, 230);
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);
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);
1450 clear_keepalive(req);
1451 ftp_send_async_message(req, LOGIN_FORBIDDEN, 530);
1457 ftp_send_async_message(req, LOGIN_OK_PASS, 230);
1462 ftp_send_async_message(req, SITE, 214);
1467 ftp_send_async_message(req, LINUX_SYST, 200);
1472 ftp_send_async_message(req, TYPE_OK, 200);
1475 #define EXTRA_FEATURES "211-Extensions supported:\r\n SIZE\r\n MDTM\r\n211 End\r\n"
1479 ftp_send_async_message(req, EXTRA_FEATURES, 211);
1486 ftp_send_async_message(req, COMMAND_OK, 200);
1491 ftp_send_async_message(req, REST_OK, 200);
1496 clear_keepalive(req);
1497 ftp_send_async_message(req, BYE, 200);
1503 req->keep_alive = 1;
1504 ftp_send_async_message(req, CLOSE, 500);
1510 Dprintk("rejecting FTP session!\n");
1515 static void ftp_timeout (tux_req_t *req, int cachemiss)
1517 Dprintk("called ftp_timeout(%p)\n", req);
1518 if (req->error != TUX_ERROR_CONN_TIMEOUT)
1520 ftp_send_async_message(req, CLOSE_TIMEOUT, 421);
1523 static void ftp_close (tux_req_t *req, int cachemiss)
1525 Dprintk("called ftp_close(%p)\n", req);
1526 ftp_send_async_message(req, CLOSE, 500);
1529 static void ftp_pre_log (tux_req_t *req)
1531 if (tux_ftp_log_retr_only && (req->ftp_command != FTP_COMM_RETR))
1534 req->status = req->ftp_command;
1537 tux_proto_t tux_proto_ftp = {
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,