2 * Copyright (c) 2007,西安邮电学院Linux兴趣小组
6 * 摘 要:处理MKD RMD DELE PASV STOR命令
12 * 修改原因:LIST与STAT中的日期格式不符合要求,在很多图形界面客户端中出现问题,故更改之。
19 * 摘 要:原来增加的命令不很符合要求,重建此文件。全部根据要求,现将命令单独在test目录中通过的逐条加入。
24 *6.16: 添加do_mkd,do_rmd, do_dele, do_retr
37 extern struct user_env user_env
;
38 extern struct run_env run_env
;
40 static void _stat_fail_450(void);
41 static void _stat_error_421(void);
42 static void _stat_error1_501(void);
43 static void _stat_error2_501(void);
44 static void _stat_error3_501(void);
45 static void _stat_fail_550(void);
46 static void _stat_success_150(void);
47 static void _stat_success_226(void);
48 static void _stat_fail_501(void);
49 static void _path_tail(char *, char *);
50 static int _get_local_ip_address(int sock
, char* ip_addr
);
51 static int _stat_mkd(const char *path
);
52 static int _stat_rmd(const char *path
);
53 static int _stat_dele(const char *path
);
54 static int _stat_retr(const char *);
55 static int _ignore_sigpipe(void);
56 static int _analysis_ipaddr(char *, char **, int *);
57 static int _chdir(const char*);
58 static int _response(const char*);
60 int failed(const char *s
);
62 int do_user(char username
[])
64 const char anonymous
[] = "anonymous";
65 const char inf_buf
[] = "331 Please send you password.\r\n";
66 const char no_anonymous
[] = "555 Anonymous not allowed on this server.\r\n";
67 const char noname
[] = "500 USER: command requires a parameter.\r\n";
68 const char logged
[] = "503 You have already logged in.\r\n";
70 if (username
[0] == '\0') {
72 debug_printf("%s\n", noname
);
76 if (user_env
.login_in
== TRUE
) {
78 debug_printf("%s\n", logged
);
82 if (strcmp(username
, anonymous
) == 0){
83 if(run_env
.anonymous_enable
){
84 strcpy(user_env
.user_name
, username
);
86 debug_printf("%s\n", inf_buf
);
88 _response(no_anonymous
);
89 debug_printf("%s\n", no_anonymous
);
92 /*anonymous client authentication*/
94 strcpy(user_env
.user_name
, username
);
96 debug_printf("%s\n", inf_buf
);
101 /*implement of USER*/
103 static char get_hex(const char *buf
)
106 strncpy(tmp
, buf
, 2);
107 return (char) strtol(tmp
, NULL
, 16);
110 /*implement of PASS*/
111 int do_pass(char *pass
)
117 const char log_error
[] = "Login failed!\r\n";
118 const char logged
[] = "503 You have already logged in.\r\n";
122 char *line
= NULL
, *tmp
;
123 int i
, j
, pass_len
, id
;
125 if (user_env
.login_in
== TRUE
) {
130 if (strcmp(user_env
.user_name
, "anonymous") == 0) {
131 snprintf(mess
, 50, "230 User anonymous logged in.\r\n");
132 user_env
.login_in
= TRUE
;
133 user_env
.enable_upload
= FALSE
;
138 if ((fp
= fopen(run_env
.user_pass_file
, "r")) == NULL
) {
139 write_log("open user_pass_file error",0);
140 _response(log_error
);
144 while ((k
= getline(&line
, &len
, fp
)) != -1) {
145 fscanf(fp
, "%d", &id
);
163 if (strcmp(name
, user_env
.user_name
) == 0)
168 snprintf(mess
, 50, "530 Login incorrect.\r\n");
174 user_env
.user_id
= id
;
176 for (i
= 0, j
= 0; tmp
[i
] != '\n' && j
< 6; i
++) {
183 user_env
.enable_upload
= TRUE
;
188 for (j
= 0; j
< 16; ) {
189 password
[j
++] = get_hex(tmp
+i
);
194 pass_len
=strlen(pass
);
195 MD5((const unsigned char *)pass
, pass_len
, (unsigned char *)md
);
199 if (!memcmp(password
, md
, 16) ) {
200 snprintf(mess
, 50, "230 User %s logged in.\r\n", user_env
.user_name
);
201 user_env
.login_in
= TRUE
;
205 snprintf(mess
, 50, "530 Login incorrect.\r\n");
212 /*implement of STAT*/
214 static char *_format_time(struct stat
*stat_buf
, char *str
)
216 const char month
[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
217 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
220 gmtime_r(&(stat_buf
->st_mtime
), &tmp
);
222 if (S_ISDIR(stat_buf
->st_mode
)) {
223 snprintf(str
, strlen(str
), "%s %2d %4d", month
[tmp
.tm_mon
], tmp
.tm_mday
, tmp
.tm_year
+ 1900);
226 snprintf(str
, strlen(str
), "%s %2d %2d:%2d", month
[tmp
.tm_mon
], tmp
.tm_mday
, tmp
.tm_hour
, tmp
.tm_min
);
232 static char *_get_line_info(struct stat
*stat_buf
, char *buf
, int *width
)
234 char att
[11] = "----------", tm
[26];
235 char time_str_buff
[] = "Dec 12, 18:00";
236 unsigned int t
= S_IRUSR
;
239 if (S_ISREG(stat_buf
->st_mode
)) {
242 else if (S_ISDIR(stat_buf
->st_mode
)) {
245 else if (S_ISCHR(stat_buf
->st_mode
)) {
248 else if (S_ISBLK(stat_buf
->st_mode
)) {
251 else if (S_ISFIFO(stat_buf
->st_mode
)) {
254 else if (S_ISLNK(stat_buf
->st_mode
)) {
257 else if (S_ISSOCK(stat_buf
->st_mode
)) {
260 for (i
= 1;i
< 10;i
++,t
>>= 1) {
261 if (stat_buf
->st_mode
& t
) {
263 case 1: att
[i
] = 'r';
265 case 2: att
[i
] = 'w';
267 case 0: att
[i
] = 'x';
271 if (snprintf(tm
, 25, "%s", _format_time(stat_buf
, time_str_buff
)) == -1) {
272 write_log("Read system time error!", 0);
274 if (snprintf(buf
, MAX_PATH
, "%s% *d %*s %*s% *d %s", att
, width
[2], (size_t)stat_buf
->st_nlink
, width
[0],
275 run_env
.visible_user_name
,width
[1], run_env
.visible_group_name
,width
[3],
276 (size_t)stat_buf
->st_size
, tm
) == -1){
277 write_log("The path string is overflow!", 0);
282 static int _get_int_len(int n
)
285 for (i
= 1;n
/= 10;i
++) {
291 static int _stat_no_arg(void)
293 char msg
[MAX_MSG_LEN
]={0};
294 if (snprintf(msg
, MAX_MSG_LEN
, "211-Status for user %s from %s:\r\n"
295 "211-Stored %d files,%d KB\r\n211-Retrieved %d files,%d KB\r\n211 End of Status.\r\n",
296 user_env
.user_name
, user_env
.client_ip
, user_env
.upload_files
,
297 user_env
.upload_kbytes
, user_env
.download_files
, user_env
.download_kbytes
) == -1) {
298 write_log("The message is overflow.",0);
300 return _response(msg
);
303 static int _stat_with_arg(const char *cmd_arg
)
305 char buf
[MAX_PATH
], full_path
[MAX_PATH
], tmp
[MAX_PATH
];
306 const char not_found
[] = "450 Target path doesn't exist.\r\n";
307 struct dirent
*direntp
;
309 struct stat stat_buf
;
310 int max_width
[4] = {0}; /*max length of user name, group name,link number and the file length number*/
313 if (*cmd_arg
== '/') {
314 if (snprintf(buf
, MAX_PATH
, "%s", cmd_arg
) == -1) {
315 write_log("Path string overflows.", 0);
319 if (snprintf(buf
, MAX_PATH
, "%s%s", user_env
.current_path
, cmd_arg
) == -1) {
320 write_log("Path string overflows.", 0);
324 strcpy(full_path
, buf
); /*the length of buf won't greater than the full_path so it's safe.*/
326 if (!(target_dir
= opendir(buf
))) {
327 _response(not_found
);
328 return closedir(target_dir
);
331 max_width
[0] = (t
= strlen(run_env
.visible_user_name
)) > max_width
[0]?t
:max_width
[0];
332 max_width
[1] = (t
= strlen(run_env
.visible_group_name
)) > max_width
[1]?t
:max_width
[1];
334 while ((direntp
= readdir(target_dir
)) != NULL
) {
335 if (snprintf(buf
, MAX_PATH
, "%s/%s", full_path
, direntp
->d_name
) == -1) {
336 write_log("Path string overflows.", 0);
339 if (stat(buf
, &stat_buf
) == -1) {
340 write_log("Read local file status error", 0);
341 closedir(target_dir
);
345 max_width
[2] = (t
= _get_int_len(stat_buf
.st_nlink
)) > max_width
[2]?t
:max_width
[2];
346 max_width
[3] = (t
= _get_int_len(stat_buf
.st_size
)) > max_width
[3]?t
:max_width
[3];
348 rewinddir(target_dir
);
350 if (snprintf(buf
, MAX_PATH
, "211-Status of %s\r\n", cmd_arg
) == -1) {
351 write_log("Path string overflows.",0);
356 while ((direntp
= readdir(target_dir
)) != NULL
) {
357 if (*(direntp
->d_name
) == '.') {
360 if (snprintf(buf
, MAX_PATH
,"%s/%s", full_path
, direntp
->d_name
) == -1) {
361 write_log("Path string overflows.", 0);
364 if (stat(buf
, &stat_buf
) == -1) {
365 write_log("Read local file status error", 0);
366 closedir(target_dir
);
369 if (snprintf(buf
, MAX_PATH
, "211-%s %s\r\n", _get_line_info(&stat_buf
, tmp
, max_width
),
370 direntp
->d_name
) == -1) {
371 write_log("Path string overflows.", 0);
376 if (snprintf(buf
, MAX_PATH
, "211 End of Status.\r\n") == -1) {
377 write_log("Path string overflows.", 0);
380 return closedir(target_dir
);
383 int do_stat(const char *cmd_arg
)
385 if (!strlen(cmd_arg
)) {
386 return _stat_no_arg();
389 return _stat_with_arg(cmd_arg
);
391 /*end of the implement of STAT*/
393 int do_list(char *filename
)
395 int m_width
[4]={3,10,10,10};
398 char each_dir_inf
[BUF_LEN
] = {0};
399 char buf
[BUF_LEN
] = {0};
400 const char finished
[] = "226 Transfer complete.\r\n";
401 const char success
[] = "150 Opening ASCII mode data connection for file list.\r\n";
402 const char fail
[] = "450 No such file or directory.\r\n";
405 struct stat file_inf
;
406 char user_path
[PATH_NAME_LEN
] ={""};
407 char inte_dir_inf
[BUF_LEN
]={0};
412 if(filename
[0]!='/') {
413 if (strcmp(user_env
.current_path
, "/") != 0) {
414 snprintf(buf
, BUF_LEN
, "%s/%s", user_env
.current_path
, filename
);
416 snprintf(buf
, BUF_LEN
, "%s%s", user_env
.current_path
, filename
);
420 snprintf(buf
, BUF_LEN
, "%s", filename
);
423 debug_printf("buf=%s\n", buf
);
425 wordexp(buf
, &wxp
, 0);
427 for (i
=0; i
< wxp
.we_wordc
; i
++){
432 if (stat(w
[i
], &file_inf
) == 0) {
433 if (!S_ISDIR(file_inf
.st_mode
)
434 || (wxp
.we_wordc
!=1 || strcmp(w
[0], buf
) != 0)) {
435 snprintf(inte_dir_inf
, BUF_LEN
, "%s %s\r\n",
436 _get_line_info(&file_inf
, each_dir_inf
, m_width
),
438 write(user_env
.data_fd
, inte_dir_inf
,
439 strlen(inte_dir_inf
));
444 debug_printf("w[i]=%s\n", w
[i
]);
450 debug_printf("Get here with %s\n", w
[i
]);
452 if((dir_inf_str
= opendir(w
[i
])) != NULL
){
453 while((dirp
= readdir(dir_inf_str
)) != NULL
){
454 if (*(dirp
->d_name
) == '.') {
458 memset(each_dir_inf
, 0, BUF_LEN
);
459 memset(inte_dir_inf
, 0, BUF_LEN
);
460 snprintf(user_path
, PATH_NAME_LEN
, "%s/%s", w
[i
], dirp
->d_name
);
461 if(stat(user_path
, &file_inf
) != -1){
462 snprintf(inte_dir_inf
, BUF_LEN
, "%s %s\r\n",
463 _get_line_info(&file_inf
, each_dir_inf
, m_width
),
465 write(user_env
.data_fd
, inte_dir_inf
,
466 strlen(inte_dir_inf
));
473 closedir(dir_inf_str
);
481 close(user_env
.data_fd
);
487 int do_mkd(const char *path
) /*处理命令MKD的入口*/
489 char str
[PATH_NAME_LEN
] = {""};
490 if (user_env
.enable_upload
== 1) { /*判断权限*/
491 if (path
[0] == '/') { /*参数是路径名?*/
492 path
= strcat(str
, path
);
494 strcpy(str
, user_env
.current_path
);
495 if(str
[strlen(str
)-1] != '/')
497 path
= strcat(str
, path
);
499 if(_stat_mkd(path
) == 0) {
510 static int _stat_mkd(const char *path
)
512 char buf
[50+PATH_NAME_LEN
] = {};
514 debug_printf("mkd: path=%s \r\n", path
);
515 if (mkdir(path
, S_IRWXU
) == 0) { /*创建目录成功*/
516 snprintf(buf
, 50+PATH_NAME_LEN
, "257 Directory successfully created:%s.\r\n", path
);
520 if (errno
== EEXIST
) {
523 else if (errno
== ENAMETOOLONG
) {
535 int do_rmd(const char *path
) /*处理命令RMD的入口*/
537 char str
[PATH_NAME_LEN
]={""};
538 if (user_env
.enable_upload
== 1) { /*判断权限*/
539 if (path
[0] == '/') { /*参数是路径名?*/
540 path
= strcat(str
, path
);
543 strcpy(str
, user_env
.current_path
);
544 if(str
[strlen(str
)-1] != '/') {
547 path
= strcat(str
,path
);
549 if (_stat_rmd(path
) == 0) {
560 static int _stat_rmd(const char *path
)
562 const char buf
[] = "250 RMD command successful.\r\n";
564 debug_printf("rmdir at %s \r\n", path
);
565 if (rmdir(path
) == 0) { /*删除目录成功*/
569 if(errno
== ENOENT
) {
571 } else if (errno
== ENAMETOOLONG
) {
583 int do_dele(const char *path
) /*处理命令DELE的入口*/
585 char str
[PATH_NAME_LEN
] = {""};
586 if (user_env
.enable_upload
== 1) { /*判断权限*/
587 if (path
[0] == '/') { /*参数是路径名?*/
588 path
= strcat(str
, path
);
590 strcpy(str
, user_env
.current_path
);
591 if(str
[strlen(str
)-1] != '/') {
594 path
= strcat(str
,path
);
596 if (_stat_dele(path
) == 0) {
607 int _stat_dele(const char *path
)
609 const char msg
[] = "250 File sucessfully deleted.\r\n";
611 debug_printf("dele at %s \r\n",path
);
612 if (unlink(path
) == 0) { /*删除文件成功*/
616 if (errno
== ENOENT
) {
618 } else if (errno
== ENAMETOOLONG
) {
630 static int _stat_retr(const char *path
)
634 char buf
[BUF_LEN
]={""};
636 debug_printf("retr from %s\n",path
);
638 fd
= open(path
, O_RDONLY
);
640 if((off_t
)-1 == lseek(fd
, user_env
.restartat
, SEEK_SET
)){
643 LOG_IT("lseek error.");
647 while((i
= read(fd
, buf
, BUF_LEN
)) != 0) {
649 r_close(user_env
.data_fd
);
653 write(user_env
.data_fd
, buf
, i
);
654 user_env
.download_kbytes
+= i
/1000;
657 user_env
.download_files
++;
659 r_close(user_env
.data_fd
);
660 user_env
.restartat
= 0;
664 r_close(user_env
.data_fd
);
670 int do_retr(const char *path
)
672 char str
[PATH_NAME_LEN
]={""};
673 if (strlen(path
) == 0) {
674 close(user_env
.data_fd
);
675 return failed("RETR");
677 if (path
[0] == '/') { /*参数是路径名?*/
678 path
= strcat(str
, path
);
680 strcpy(str
, user_env
.current_path
);
681 if(str
[strlen(str
)-1] != '/') {
684 path
= strcat(str
,path
);
686 return _stat_retr(path
);
690 static void _stat_fail_450(void)
692 const char msg
[] = "450 File operation failed.\r\n";
697 static void _stat_error_421(void)
699 const char msg
[] = "421 Service not available, closing control connection.\r\n";
705 static void _stat_fail_550(void)
707 const char msg
[] = "550 Requested action not taken. File unavailable.\r\n";
712 static void _stat_error1_501(void)
714 const char msg
[] = "501 Wrong arguments, the filename exists.\r\n";
718 static void _stat_error2_501(void)
721 "501 Diretory or file name is too long.\r\n";
725 static void _stat_error3_501(void)
728 "501 Arguments wrong,the file or directory does not exists!\r\n";
732 static void _stat_success_150(void)
734 const char msg
[] = "150 File status okay; about to open data connection.\r\n";
738 static void _stat_success_226(void)
740 const char msg
[] = "226 Closing data connection."
741 "Requested file-action succeed.\r\n";
745 static void _stat_fail_501(void)
747 const char msg
[] = "501 Syntax error in parameters or arguments.\r\n";
751 int do_mode(const char *arg
)
753 const char succ
[] = "200 MODE S OK.\r\n";
754 const char fail
[] = "504 Command not implemented for that parameter.\r\n";
755 if ((strlen(arg
) == 1) && ((*arg
== 's') || (*arg
== 'S'))) {
764 static int _get_local_ip_address(int sock
, char* ip_addr
)
767 int fd
= sock
, intrface
;
768 struct ifreq buf
[MAX_INTERFACES
];
771 ifc
.ifc_len
= sizeof buf
;
772 ifc
.ifc_buf
= (caddr_t
) buf
;
773 if (!ioctl(fd
, SIOCGIFCONF
, (char*)&ifc
)) {
774 intrface
= ifc
.ifc_len
/ sizeof(struct ifreq
);
775 while (intrface
-- > 0) {
776 if (!(ioctl(fd
, SIOCGIFADDR
, (char*)&buf
[intrface
]))) {
777 ip
= (inet_ntoa(((struct sockaddr_in
*)(&buf
[intrface
].ifr_addr
))->sin_addr
));
788 char ip_addr
[16] = {0}; /*I think 16 is just enough.*/
789 char port_buf
[64] = {0};
791 const char pasv_fail
[] = "425 Can't open data connection.\r\n";
794 int opt
= SO_REUSEADDR
;
796 struct sockaddr_in data
, cliaddr
;
797 unsigned int port
, port1
, port2
;
801 tv
.tv_sec
= run_env
.data_connection_timeout
;
803 bzero(&data
, sizeof(data
));
805 data
.sin_family
= AF_INET
; /*建立数据连接*/
806 data
.sin_port
= htons(data_port
);
807 data
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
811 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
813 LOG_IT("socket error in do_pasv().");
816 _get_local_ip_address(sock
, ip_addr
);
817 setsockopt(sock
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(struct timeval
));
818 setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
));
820 if (bind(sock
, (struct sockaddr
*)&data
, i
) != 0) {
821 LOG_IT("bind error in do_pasv().");
825 getsockname(sock
, (struct sockaddr
*)&data
, (socklen_t
*) &i
);
827 debug_printf("pasv: ip=%s\n", ip_addr
);
828 debug_printf("pasv: port=%d\n", ntohs(data
.sin_port
));
830 port
= ntohs(data
.sin_port
);
833 while ((tmp
= strchr(ip_addr
, '.')) != NULL
) {
838 if (listen(sock
, 1) != 0){
839 LOG_IT("listen error in do_pasv().");
843 snprintf(port_buf
, 64, "227 Entering Passive Mode (%s,%d,%d).\r\n",
844 ip_addr
, port1
, port2
);
847 ret
= accept(sock
, (struct sockaddr
*)&cliaddr
, &i
);
849 user_env
.data_fd
= ret
;
850 //write(user_env.connect_fd, pasv_ready, strlen(pasv_ready));
854 LOG_IT("accept error in do_pasv().");
855 _response(pasv_fail
);
863 const char wel
[] = "215 UNIX Type: L8\r\n";
865 if (_response(wel
) == -1) {
866 LOG_IT("write error in do_syst()");
874 const char mess
[] = "200 NOOP command successful.\r\n";
875 if (_response(mess
) == -1) {
876 LOG_IT("write error in do_noop()");
882 int do_type(char *arg
)
884 if (strcasecmp(arg
, "I") == 0) {
885 user_env
.ascii_on
= FALSE
;
886 _response("200 Type set to I.\r\n");
887 } else if (strcasecmp(arg
, "A") == 0) {
888 user_env
.ascii_on
= TRUE
;
889 _response("200 Type set to A.\r\n");
891 _response("500 Type not understood.\r\n");
898 int do_stru(char *arg
)
900 const char fail
[] = "501 'STRU' not understood.\r\n";
901 const char succ
[] = "200 Structure set to F.\r\n";
902 const char unsupported
[] = "504 Unsupported structure type.\r\n";
903 const char unknown
[] = "501 Unrecognized structure type.\r\n";
905 if (strcmp(arg
, "") == 0) {
908 } else if (strcasecmp(arg
, "F") == 0) {
910 } else if (strcasecmp(arg
, "P") == 0
911 || strcasecmp(arg
, "R") == 0) {
912 _response(unsupported
);
921 *Note! When this is called in parse_cmd, it means
922 *we received an 'ABOR' when no data connection exists.
923 *So we just reply a 226 and do nothing actually.
925 int do_abor(char *arg
)
927 const char fail
[] = "501 Can not understood.\r\n";
928 const char succ
[] = "226 Abort successful.\r\n";
930 if (strcmp(arg
, "") != 0) {
940 int do_cwd(const char *dir
)
942 if (_chdir(dir
) < 0) {
945 _response("250 Command ok.\r\n");
952 if (_chdir("..") < 0) {
955 _response("250 CDUP Command ok.\r\n");
962 char mess
[PATH_NAME_LEN
+6] = {0};
963 snprintf(mess
, 4096, "257 \"%s\"\r\n", user_env
.current_path
);
970 if (_response("350 Please send the RNTO command.\r\n") < 0) {
977 int do_rnto(const char *old_path
, const char *new_path
)
981 debug_printf("%s,%s\n", old_path
, new_path
);
983 if (user_env
.enable_upload
!= 1) {
984 _response("550 Permission denied!\r\n");
988 if (rename(old_path
, new_path
) < 0) {
991 mess
= "553 New path is a directory.\r\n";
994 mess
= "502 The files are in use now.\r\n";
997 mess
= "501 Can't rename this file.\r\n";
1002 _response("250 Command succeed.\r\n") ;
1006 int do_port(char *arg
)
1008 struct sockaddr_in client
;
1015 if (_analysis_ipaddr(arg
, &addr
, &port
) < 0) {
1019 debug_printf("addr=%s, port=%d\n", addr
, port
);
1021 bzero((char *)&client
, sizeof(client
)) ;
1022 client
.sin_port
= htons(port
);
1023 if (inet_pton(AF_INET
, addr
, &client
.sin_addr
) == 0) {
1024 _response("501 Incorrect IP address.\r\n");
1027 if (strcmp(user_env
.port_ip
, addr
) != 0){
1028 strcpy(user_env
.port_ip
, addr
);
1029 user_env
.port_connections
= 0;
1031 if (strcmp(user_env
.port_ip
, user_env
.client_ip
) != 0){
1032 if (user_env
.port_connections
>= run_env
.max_port_connections
){
1033 _response("421 Failed to create data connection.\r\n");
1036 user_env
.port_connections
++;
1038 debug_printf("user_env.port_connections=%d\n", user_env
.port_connections
);
1042 client
.sin_family
= AF_INET
;
1043 if ((_ignore_sigpipe() == -1) || ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1)) {
1044 _response("421 Failed to create data connection.\r\n");
1047 if (((retval
= connect(sock
, (struct sockaddr
*)&client
, sizeof(client
))) == -1)
1048 && ((errno
== EINTR
)||(errno
== EALREADY
))) {
1049 /*create data connection*/;
1053 while ((close(sock
) == -1) && (errno
== EINTR
))
1056 _response("421 Failed to create data connection.\r\n");
1059 _response("200 Succeed to create data connection.\r\n");
1060 user_env
.data_fd
= sock
;
1064 static int _ignore_sigpipe(void)
1066 struct sigaction act
;
1067 if (sigaction(SIGPIPE
, (struct sigaction
*)NULL
, &act
) == -1) {
1070 if (act
.sa_handler
== SIG_DFL
) {
1071 act
.sa_handler
= SIG_IGN
;
1072 if (sigaction(SIGPIPE
, &act
, (struct sigaction
*)NULL
) == -1) {
1079 static int _analysis_ipaddr(char *str
, char **re_addr
, int *re_port
)
1081 static char addr
[16];
1086 sscanf(str
, "%d,%d,%d,%d,%d,%d", &ip
[0], &ip
[1], &ip
[2], &ip
[3], &port
[0], &port
[1]);
1088 if ((ip
[i
] > 255) || (ip
[i
] < 0)) {
1093 m
= port
[0]*256 + port
[1];
1097 snprintf(addr
, 16, "%d.%d.%d.%d", ip
[0], ip
[1], ip
[2], ip
[3]);
1103 #define RESPONSE(msg) write(user_env.connect_fd, msg, strlen(msg))
1105 static int _response(const char *buf
)
1109 while (((byteswrite
= RESPONSE(buf
)) == -1)
1110 && (errno
== EINTR
))
1111 /*do nothing here*/;
1112 if (byteswrite
< 0) { /*If cannot write to socket,close all connections and kill the process*/
1113 r_close(user_env
.connect_fd
);
1115 write_log("remote host did not responsed.", 1);
1117 return (int)byteswrite
;
1120 static int _chdir(const char *cdir
)
1122 char *buffer
= NULL
;
1125 if (strlen(cdir
) == 0) {
1126 strcpy(user_env
.current_path
,"/");
1127 if (chdir("/") < 0) {
1128 write_log("chdir failed", 0);
1134 if ((chdir(cdir
)) < 0) {
1135 LOG_IT("chdir error in _chdir().");
1136 _response("501 Can't change directory.\r\n");
1140 if ((buffer
= malloc(size
)) == NULL
) {
1141 _response("550 Can't change directory.\r\n");
1142 LOG_IT("malloc failed");
1145 while ((getcwd(buffer
, size
) == NULL
) && (errno
== ERANGE
)){
1147 if((buffer
= realloc(buffer
, size
)) == NULL
){
1148 _response("550 Can't change directory.\r\n");
1149 LOG_IT("realloc failed");
1154 strcpy(user_env
.current_path
, buffer
);
1161 const char wel
[] = "221 Goodbye.\r\n";
1163 while ((write(user_env
.connect_fd
, wel
, strlen(wel
))) == -1) {
1164 LOG_IT("write error in do_quit().");
1166 close(user_env
.connect_fd
);
1168 kill(getpid(), SIGTERM
);
1172 int do_stor(char *arg
)
1174 char pathname
[MAX_PATH
]={""};
1175 const char stor_ok
[] = "226 Transfer complete.\r\n";
1181 debug_printf("****STOR; arg = %s\n", arg
);
1182 debug_printf("user_env.current_path=%s\n", user_env
.current_path
);
1184 if (!user_env
.enable_upload
) {
1185 _response("550 Permission denied.\r\n");
1186 close(user_env
.data_fd
);
1187 write_log("Attempt to write.", 1);
1192 strcpy(pathname
, run_env
.ftp_dir
);
1193 if(pathname
[strlen(pathname
)-1] != '/') {
1194 strcat(pathname
, "/");
1200 strncpy(pathname
, arg
, MAX_PATH
);
1203 strcpy(pathname
, user_env
.current_path
);
1204 if(pathname
[strlen(pathname
)-1] != '/')
1205 strcat(pathname
, "/");
1206 strcat(pathname
, arg
);
1209 debug_printf("pathname=%s.\n", pathname
);
1211 fd
= open(pathname
, O_RDWR
|O_CREAT
);
1213 _response("550 Permission denied.\r\n");
1214 close(user_env
.data_fd
);
1215 LOG_IT("Open error in do_stor().");
1218 if ((off_t
)-1 == lseek(fd
, user_env
.restartat
, SEEK_SET
)){
1220 LOG_IT("lseek error in do_stor().");
1223 _stat_success_150();
1225 debug_printf("%s create OK! \n", pathname
);
1227 sd
= user_env
.data_fd
;
1229 rsize
= read(sd
, buff
, BUF_LEN
);
1234 LOG_IT("Read socket error in do_stor().");
1237 write(fd
, buff
, rsize
);
1238 user_env
.upload_kbytes
+= rsize
/1024;
1242 user_env
.restartat
= 0;
1244 user_env
.upload_files
++;
1246 debug_printf("%d files, %d KB.\n", user_env
.upload_files
, user_env
.upload_kbytes
);
1251 int do_rest(const char *arg
)
1254 const char failed_msg
[] = "501 REST needs a numeric parameter\r\n";
1255 const char succ_msg
[] = "350 Restarting successfully."
1256 " Send STORE or RETRIEVE to initiate transfer\r\n";
1257 const char restrict_msg
[] = "501 REST: Resuming transfers not"
1258 " allowed in ASCII mode\r\n";
1260 user_env
.restartat
= (off_t
) strtoull(arg
, &endptr
, 10);
1261 if (*endptr
!= 0 || user_env
.restartat
< (off_t
) 0) {
1262 user_env
.restartat
= 0;
1263 _response(failed_msg
);
1266 if (user_env
.ascii_on
&& user_env
.restartat
!= 0) {
1267 _response(restrict_msg
);
1270 _response(succ_msg
);
1276 int do_size(const char *name
)
1278 const char fail_msg
[] = "550 Could not get file size.\r\n";
1279 const char fail_msg2
[] = "550 I can only retrieve regular files.\r\n";
1280 char buf
[MAX_MSG_LEN
] = {0,};
1284 _response(fail_msg
);
1286 } else if (stat(name
, &st
)) {
1287 _response(fail_msg
);
1288 write_log("stat failed.", 0);
1290 } else if (!S_ISREG(st
.st_mode
)) {
1291 _response(fail_msg2
);
1294 snprintf(buf
, MAX_MSG_LEN
, "%d %llu\r\n", 213,
1295 (unsigned long long)st
.st_size
);
1301 int do_site(const char *args
)
1303 const char ok_msg
[] = "200 Command okay.\r\n";
1304 const char bad_msg
[] = "550 Bad file.\r\n";
1305 const char fail_msg
[] = "550 Can't chmod.\r\n";
1306 const char no_msg
[] = "502 Command not implemented.\r\n";
1308 if (!strncasecmp("CHMOD ", args
, 6)) {
1310 const char *filename
;
1311 char buf
[256] = {0,};
1313 if (!user_env
.enable_upload
) {
1314 _response("550 Permission denied.\r\n");
1315 LOG_IT("Attempt to write.");
1319 mode
= strtol(args
, (char**)&args
, 8);
1320 while (*args
&& isspace(*args
))
1324 debug_printf("mode=%d, filename=%s\n", mode
, args
);
1326 if (!getcwd(buf
, 128) ||
1327 strlen(buf
) + strlen(filename
) + 1 > 256) {
1333 strcat(buf
, filename
);
1334 if (-1 == chmod(filename
, mode
)) {
1335 _response(fail_msg
);
1336 LOG_IT("chmod failed");
1347 int do_help(const char *args
)
1349 const char help
[] = "214-The following commands are implemented.\r\n"
1350 "214-USER QUIT PASS SYST HELP PORT PASV LIST\r\n"
1351 "214-NLST RETR STOR TYPE MKD RMD DELE PWD\r\n"
1352 "214-CWD SITE CDUP RNFR RNTO NOOP NLST\r\n"
1353 "214 End of list.\r\n";
1354 const char helpsite
[] = "214-The following SITE commands are implemented.\r\n"
1355 "214-CHMOD HELP\r\n"
1356 "214 End of list.\r\n";
1357 const char nohelp
[] = "214 There is no help for that command.\r\n";
1359 if (!strlen(args
)) {
1361 } else if (!strcasecmp(args
, "SITE")) {
1362 _response(helpsite
);
1369 /*reply to wrong or unsupported commands*/
1370 int failed(const char *s
)
1372 char msg500
[MAX_PATH
] = {0};
1375 if ((m_len
= snprintf(msg500
, MAX_PATH
,
1376 "500 \'%s\' command is not supported.\r\n", s
)) >= MAX_PATH
|| m_len
== -1) {
1377 write_log("Too long command got.", 0);
1383 /*implement of NLST*/
1384 int do_nlst(const char *path
)
1387 const char finish
[] = "226 Transfer complete.\r\n";
1388 const char success
[] = "150 Opening ASCII mode data connection for file list.\r\n";
1389 const char fail
[] = "450 No such file or directory.\r\n";
1390 struct stat stat_buf
;
1392 struct dirent
*direntp
;
1393 char buf
[BUF_LEN
] = {0};
1398 if ((user_env
.current_path
[strlen(user_env
.current_path
) - 1]) == '/') {
1399 snprintf(buf
, BUF_LEN
, "%s%s", user_env
.current_path
, path
);
1401 snprintf(buf
, BUF_LEN
, "%s/%s", user_env
.current_path
, path
);
1405 snprintf(buf
, BUF_LEN
, "%s", path
);
1408 debug_printf("buf=\'%s\'\n", buf
);
1410 wordexp(buf
, &wxp
, 0);
1411 words
= wxp
.we_wordv
;
1413 if (wxp
.we_wordc
< 1) {
1420 if (wxp
.we_wordc
== 1) {
1421 if (stat(words
[0], &stat_buf
) == -1) {
1426 if (S_ISDIR(stat_buf
.st_mode
)) {
1427 _path_tail(buf
, words
[0]);
1428 if((target_dir
= opendir(buf
)) == NULL
) {
1431 while ((direntp
= readdir(target_dir
)) != NULL
&& direntp
->d_name
[0] != '.') {
1432 write(user_env
.data_fd
, direntp
->d_name
, strlen(direntp
->d_name
));
1433 write(user_env
.data_fd
, "\n", 1);
1440 for (i
= 0; i
< (int)wxp
.we_wordc
; i
++) {
1441 if (words
[i
][0] != '.') {
1442 write(user_env
.data_fd
, words
[i
], strlen(words
[i
]));
1443 write(user_env
.data_fd
, "\n", 1);
1447 suc
: _response(finish
);
1449 end
: close(user_env
.data_fd
);
1454 static void _path_tail(char *buf
, char *name
)
1459 if ((strlen(buf
) + strlen(name
)) >= BUF_LEN
) {
1463 for (i
= strlen(buf
); i
>= 0; i
--) {
1464 if (buf
[i
] == '/') {
1471 strcat(buf
, name
); /*It's safe*/
1474 /*end of implement NLST*/