|
發表者 |
討論內容 |
冷日 (冷日) |
發表時間:2007/9/6 10:24 |
- Webmaster

- 註冊日: 2008/2/19
- 來自:
- 發表數: 15771
|
- [分享]vsftpd patch for utf-8 Server Big-5 Client
- 前幾天 "不小心" 把自己家裡的主機內的檔案名, 都改成 UTF-8 來處理, 在 samba 上頭是可以很正常的處理, 不過.... 發現在使用 ftp 時, 問題就不小了.
如果是支援 UTF-8 的 ftp client, 是可以正常運作, 如 gftp, smartftp....
不過, 在用了一天的 smartftp 之後, 實在發現和之前用 filezilla 的習慣大不相同, 用起來實在不習慣.
原本打算動手改 filezilla 的程式碼.... 只是, 在 windows 下頭, 似乎沒有 iconv 可以用... 又懶的去找 win32 可以用的函式... 所以, 就直接改 server 上的 vsftpd 來配合非 UTF-8 的 ftp client.
修改的構想主要來自 proftpd 的 iconv patch: http://home.h01.itscom.net/para/software/misc/proftpd-iconv/index-e.html
我是修改 Debian 的 vsftpd 2.0.1 的版本. patch 如下:
代碼: |
diff -Nur vsftpd-2.0.1/features.c vsftpd-2.0.1.patched/features.c --- vsftpd-2.0.1/features.c 2004-07-02 19:22:45.000000000 +0800 +++ vsftpd-2.0.1.patched/features.c 2005-02-22 12:21:56.000000000 +0800 @@ -25,6 +25,7 @@ vsf_cmdio_write_raw(p_sess, " EPSV "); vsf_cmdio_write_raw(p_sess, " MDTM "); vsf_cmdio_write_raw(p_sess, " PASV "); + vsf_cmdio_write_raw(p_sess, " ICNV "); if (tunable_ssl_enable) { vsf_cmdio_write_raw(p_sess, " PBSZ "); diff -Nur vsftpd-2.0.1/ftpcmdio.c vsftpd-2.0.1.patched/ftpcmdio.c --- vsftpd-2.0.1/ftpcmdio.c 2004-07-02 19:23:02.000000000 +0800 +++ vsftpd-2.0.1.patched/ftpcmdio.c 2005-02-22 11:48:44.000000000 +0800 @@ -7,6 +7,9 @@ * Routines applicable to reading and writing the FTP command stream. */ +#include <stdlib.h> +#include <string.h> +#include "utility.h" #include "ftpcmdio.h" #include "ftpcodes.h" #include "str.h" @@ -170,6 +173,16 @@ control_getline(p_cmd_str, p_sess); str_split_char(p_cmd_str, p_arg_str, ' '); str_upper(p_cmd_str); + if (!str_isempty(p_arg_str)) { + char *tmp_str; + + tmp_str = remote2local(str_getbuf(p_arg_str)); + if (tmp_str != NULL) { + str_empty(p_arg_str); + str_append_text(p_arg_str, tmp_str); + vsf_sysutil_free(tmp_str); + } + } if (tunable_log_ftp_protocol) { static struct mystr s_log_str; diff -Nur vsftpd-2.0.1/ls.c vsftpd-2.0.1.patched/ls.c --- vsftpd-2.0.1/ls.c 2004-07-02 19:23:34.000000000 +0800 +++ vsftpd-2.0.1.patched/ls.c 2005-02-22 11:48:56.000000000 +0800 @@ -7,6 +7,9 @@ * Would you believe, code to handle directory listing. */ +#include <stdlib.h> +#include <string.h> +#include "utility.h" #include "ls.h" #include "access.h" #include "str.h" @@ -363,6 +366,7 @@ const struct vsf_sysutil_statbuf* p_stat) { static struct mystr s_tmp_str; + char *tmp_filename; filesize_t size = vsf_sysutil_statbuf_get_size(p_stat); /* Permissions */ str_alloc_text(p_str, vsf_sysutil_statbuf_get_perms(p_stat)); @@ -432,7 +436,13 @@ tunable_use_localtime)); str_append_char(p_str, ' '); /* Filename */ - str_append_str(p_str, p_filename_str); + tmp_filename = local2remote(str_getbuf(p_filename_str)); + if (tmp_filename == NULL) + str_append_str(p_str, p_filename_str); + else { + str_append_text(p_str, tmp_filename); + vsf_sysutil_free(tmp_filename); + } str_append_text(p_str, " "); } diff -Nur vsftpd-2.0.1/parseconf.c vsftpd-2.0.1.patched/parseconf.c --- vsftpd-2.0.1/parseconf.c 2004-07-02 19:23:56.000000000 +0800 +++ vsftpd-2.0.1.patched/parseconf.c 2005-02-22 11:49:12.000000000 +0800 @@ -94,6 +94,7 @@ { "ssl_sslv3", &tunable_sslv3 }, { "ssl_tlsv1", &tunable_tlsv1 }, { "tilde_user_enable", &tunable_tilde_user_enable }, + { "enable_iconv", &tunable_enable_iconv }, { 0, 0 } }; @@ -158,6 +159,8 @@ { "rsa_cert_file", &tunable_rsa_cert_file }, { "dsa_cert_file", &tunable_dsa_cert_file }, { "ssl_ciphers", &tunable_ssl_ciphers }, + { "local_charset", &tunable_local_charset }, + { "remote_charset", &tunable_remote_charset }, { 0, 0 } }; diff -Nur vsftpd-2.0.1/postlogin.c vsftpd-2.0.1.patched/postlogin.c --- vsftpd-2.0.1/postlogin.c 2004-07-02 19:24:01.000000000 +0800 +++ vsftpd-2.0.1.patched/postlogin.c 2005-02-22 15:54:14.000000000 +0800 @@ -5,6 +5,9 @@ * postlogin.c */ +#include <stdlib.h> +#include <string.h> +#include "utility.h" #include "postlogin.h" #include "session.h" #include "oneprocess.h" @@ -157,6 +160,29 @@ { handle_pwd(p_sess); } + else if (str_equal_text(&p_sess->ftp_cmd_str, "ICNV")) + { + str_upper(&p_sess->ftp_arg_str); + if (str_equal_text(&p_sess->ftp_arg_str, "ON")) + { + tunable_enable_iconv = 1; + vsf_cmdio_write(p_sess, FTP_CWDOK, "enable iconv()."); + } + else if (str_equal_text(&p_sess->ftp_arg_str, "OFF")) + { + tunable_enable_iconv = 0; + vsf_cmdio_write(p_sess, FTP_CWDOK, "disable iconv()."); + } + else { + if (tunable_enable_iconv) { + vsf_cmdio_write(p_sess, FTP_CWDOK, "iconv() enabled."); + } + else + { + vsf_cmdio_write(p_sess, FTP_CWDOK, "iconv() disabled."); + } + } + } else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") || str_equal_text(&p_sess->ftp_cmd_str, "XCWD")) { @@ -404,6 +430,7 @@ static void handle_pwd(struct vsf_session* p_sess) { + char *tmp_str; static struct mystr s_cwd_buf_mangle_str; static struct mystr s_pwd_res_str; str_getcwd(&s_cwd_buf_mangle_str); @@ -411,7 +438,13 @@ str_replace_text(&s_cwd_buf_mangle_str, """, """"); /* Enclose pathname in quotes */ str_alloc_text(&s_pwd_res_str, """); - str_append_str(&s_pwd_res_str, &s_cwd_buf_mangle_str); + tmp_str = local2remote(str_getbuf(&s_cwd_buf_mangle_str)); + if (tmp_str == NULL) + str_append_str(&s_pwd_res_str, &s_cwd_buf_mangle_str); + else { + str_append_text(&s_pwd_res_str, tmp_str); + vsf_sysutil_free(tmp_str); + } str_append_text(&s_pwd_res_str, """); vsf_cmdio_write_str(p_sess, FTP_PWDOK, &s_pwd_res_str); } @@ -435,6 +468,24 @@ } else { + if (tunable_enable_iconv) { + char *tmp_str; + + tmp_str = local2remote(str_getbuf(&p_sess->ftp_arg_str)); + if (tmp_str != NULL) { + str_empty(&p_sess->ftp_arg_str); + str_append_text(&p_sess->ftp_arg_str, tmp_str); + vsf_sysutil_free(tmp_str); + retval = str_chdir(&p_sess->ftp_arg_str); + if (retval == 0) + { + /* Handle any messages */ + vsf_banner_dir_changed(p_sess, FTP_CWDOK); + vsf_cmdio_write(p_sess, FTP_CWDOK, "Directory successfully changed."); + return; + } + } + } vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to change directory."); } } @@ -640,8 +691,29 @@ opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly); if (vsf_sysutil_retval_is_error(opened_file)) { - vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); - return; + if (tunable_enable_iconv) { + char *tmp_str; + + tmp_str = local2remote(str_getbuf(&p_sess->ftp_arg_str)); + if (tmp_str != NULL) { + str_empty(&p_sess->ftp_arg_str); + str_append_text(&p_sess->ftp_arg_str, tmp_str); + vsf_sysutil_free(tmp_str); + opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly); + if (vsf_sysutil_retval_is_error(opened_file)) { + vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); + return; + } + } + else { + vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); + return; + } + } + else { + vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); + return; + } } vsf_sysutil_fstat(opened_file, &s_p_statbuf); /* No games please */ @@ -1623,7 +1695,7 @@ vsf_cmdio_write_raw(p_sess, " RNTO SITE SIZE SMNT STAT STOR STOU STRU SYST TYPE USER XCUP XCWD XMKD "); vsf_cmdio_write_raw(p_sess, -" XPWD XRMD "); +" XPWD XRMD ICNV "); vsf_cmdio_write(p_sess, FTP_HELP, "Help OK."); } diff -Nur vsftpd-2.0.1/tunables.c vsftpd-2.0.1.patched/tunables.c --- vsftpd-2.0.1/tunables.c 2004-07-02 19:26:17.000000000 +0800 +++ vsftpd-2.0.1.patched/tunables.c 2005-02-22 12:17:52.000000000 +0800 @@ -66,6 +66,7 @@ int tunable_sslv3 = 0; int tunable_tlsv1 = 1; int tunable_tilde_user_enable = 0; +int tunable_enable_iconv = 0; unsigned int tunable_accept_timeout = 60; unsigned int tunable_connect_timeout = 60; @@ -115,4 +116,7 @@ const char* tunable_rsa_cert_file = "/usr/share/ssl/certs/vsftpd.pem"; const char* tunable_dsa_cert_file = 0; const char* tunable_ssl_ciphers = "DES-CBC3-SHA"; +const char* tunable_local_charset = "UTF-8"; +const char* tunable_remote_charset = "BIG5"; + diff -Nur vsftpd-2.0.1/tunables.h vsftpd-2.0.1.patched/tunables.h --- vsftpd-2.0.1/tunables.h 2004-06-29 07:08:31.000000000 +0800 +++ vsftpd-2.0.1.patched/tunables.h 2005-02-22 11:50:27.000000000 +0800 @@ -62,6 +62,7 @@ extern int tunable_sslv3; /* Allow SSLv3 */ extern int tunable_tlsv1; /* Allow TLSv1 */ extern int tunable_tilde_user_enable; /* Support e.g. ~chris */ +extern int tunable_enable_iconv; /* Convert filename use iconv */ /* Integer/numeric defines */ extern unsigned int tunable_accept_timeout; @@ -110,6 +111,8 @@ extern const char* tunable_rsa_cert_file; extern const char* tunable_dsa_cert_file; extern const char* tunable_ssl_ciphers; +extern const char* tunable_local_charset; +extern const char* tunable_remote_charset; #endif /* VSF_TUNABLES_H */ diff -Nur vsftpd-2.0.1/utility.c vsftpd-2.0.1.patched/utility.c --- vsftpd-2.0.1/utility.c 2004-07-02 19:26:30.000000000 +0800 +++ vsftpd-2.0.1.patched/utility.c 2005-02-22 14:05:46.000000000 +0800 @@ -5,6 +5,13 @@ * utility.c */ +#include <stdarg.h> +#include <iconv.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "tunables.h" #include "utility.h" #include "sysutil.h" #include "str.h" @@ -50,3 +57,71 @@ vsf_sysutil_exit(0); } +char * +local2remote(const char *buf) +{ + char *in_ptr; + char *out_ptr; + size_t inbytesleft, outbytesleft; + char *p; + iconv_t ic; + + if (tunable_enable_iconv == 0) return NULL; + ic = iconv_open(tunable_remote_charset, tunable_local_charset); + if (ic == (iconv_t)(-1)) return NULL; + iconv(ic, NULL, NULL, NULL, NULL); + + inbytesleft = strlen(buf); + outbytesleft = inbytesleft * 6; + p = vsf_sysutil_malloc(outbytesleft+1); + + in_ptr = buf; + out_ptr = p; + while (inbytesleft) { + if (iconv(ic, &in_ptr, &inbytesleft, &out_ptr, &outbytesleft) == (size_t)(-1)) { + iconv_close(ic); + vsf_sysutil_free(p); + return NULL; + } + } + + *out_ptr = 0; + + iconv_close(ic); + return p; +} + +char * +remote2local(const char *buf) +{ + char *in_ptr; + char *out_ptr; + size_t inbytesleft, outbytesleft; + char *p; + iconv_t ic; + + if (tunable_enable_iconv == 0) return NULL; + ic = iconv_open(tunable_local_charset, tunable_remote_charset); + if (ic == (iconv_t)(-1)) return NULL; + iconv(ic, NULL, NULL, NULL, NULL); + + inbytesleft = strlen(buf); + outbytesleft = inbytesleft * 6; + p = vsf_sysutil_malloc(outbytesleft+1); + + in_ptr = buf; + out_ptr = p; + while (inbytesleft) { + if (iconv(ic, &in_ptr, &inbytesleft, &out_ptr, &outbytesleft) == (size_t)(-1)) { + iconv_close(ic); + vsf_sysutil_free(p); + return NULL; + } + } + + *out_ptr = 0; + + iconv_close(ic); + return p; +} + diff -Nur vsftpd-2.0.1/utility.h vsftpd-2.0.1.patched/utility.h --- vsftpd-2.0.1/utility.h 2004-04-16 06:46:29.000000000 +0800 +++ vsftpd-2.0.1.patched/utility.h 2005-02-22 11:47:51.000000000 +0800 @@ -40,5 +40,7 @@ */ void vsf_exit(const char* p_text); +char *local2remote(const char *buf); +char *remote2local(const char *buf); #endif
|
可以到這兒抓 http://www.teatime.com.tw/~tommy/linux/vsftpd_iconv.patch
如果是使用 Debian Sarge, 也可以直接用這個: http://www.teatime.com.tw/~tommy/debian/vsftpd_2.0.1-11_i386.deb
在使用這個 patch 之後, 你可以在 vsftpd.conf 中指定下面三個參數
代碼: | enable_iconv=YES local_charset=UTF-8 remote_charset=BIG5
|
local_charset 是主機檔案名稱使用的編碼. 內定為 UTF-8. remote_charset 是 ftp client 的編碼. 內定為 BIG5. enable_iconv 預設是關閉的, 也就是所有的動作應該都與沒加上這個 patch 時一樣. 如果設為 true/yes 時, 就會使用 iconv 來轉換檔名.
動作如下: 1. 所有的 client 送來的指令, 參數, 檔案或路徑名稱, 會使用 iconv 由 remote_charset 轉成 local_charset. 所以, 實際存取是使用 local_charset 的編碼. 2. 在 ls 指令時, 要送出檔名之前, 會用 iconv 由 local_charset 轉成 remote_charset 再送出. 3. 如果轉碼的動作是失敗的, 就不做轉碼的動作. 4. 加上一個 icnv on/off 指令 (非 ftp 標準), 可以讓 client 決定是否打開這個功能. 5. 主機上頭的檔案存取, 如果在轉成 local_charset 時, 存取失敗的話, 就假設該檔案或路徑為 remote_charset 的編碼格式, 再試一次.
以上述主機使用 UTF-8, client 使用 Big5 的情形下, 不管主機上頭的檔案路徑名稱是用 UTF-8 或 Big5, 都會轉成 Big5 送到 client 上頭, 所以當我們使用像 filezilla 之類不支援 UTF-8 的程式時, 所收到的都會是 Big5 編碼的資料. 如果我們使用支援 UTF-8 的 client 時, 如 gftp, 會發現, 反而原本在 UTF-8 的檔名, 在轉成 Big5 之後, 反而看不到正確的名稱. 此時, 可以使用上述的 icnv off 指令 (gftp 使用 site icnv off, 其他程式可能用 quote icnv off) 把轉碼的動作關閉, 就可以正常看到 UTF-8 編碼的檔案.
而在檔案抓取或更換目錄時, 會先用 UTF-8 試一次, 如果失敗, 再用 Big5 試一次. 以確定主機上頭的檔名無論是 Big5 或 UTF-8 都可以被存取.
而在檔案儲存或建立目錄時, 主機上只會使用 UTF-8 來編碼.
|
|
|
冷日 (冷日) |
發表時間:2007/9/6 10:25 |
- Webmaster

- 註冊日: 2008/2/19
- 來自:
- 發表數: 15771
|
- [分享]vsftpd iconv patch
- 修改幾個會出問題的指令. 如: rmdir, dele, rename, size, chmod.
新的 patch 可以到這兒抓 http://www.teatime.com.tw/~tommy/linux/vsftpd_iconv.patch
如果是使用 Debian Sarge, 也可以直接用這個: http://www.teatime.com.tw/~tommy/debian/vsftpd_2.0.1-11_i386.deb
|
|
|