sftp:5 解決編その2 SFTP の文字化け問題解決
最終章はソースコードを直接いじり、文字化け問題を解決しよう。
その前に、使用する環境のプロファイルを説明しよう。
使用環境
Debian を用いているため、apt を用いて sshのソースを取得する。
apt-get source ssh
そして、sftp-server.c を以下のように修正。
#endif + + #include "sftp_iconv.c" /* input and output queue */ Buffer iqueue; Buffer oqueue;
sftp_iconv.c を作成する。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iconv.h> #include <errno.h> #include <dirent.h> #include <unistd.h> #include <glib.h> //#define SFTP_ICONV_DEBUG 1 #define SFTP_HIDE_PARENT_DIR 1 #ifdef SFTP_ICONV_DEBUG # define DEBUG_FILE "/tmp/sftp-out.txt" void sftp_print(const char* string,const char* printpath); void sftp_printInt(const char* string, int i); void sftp_putcs(const char* string, const char* printpath,int length); #else //SFTP_ICONV_DEBUG # define sftp_print(a,b) # define sftp_printInt(a,b) # define sftp_putcs(a,b,c) #endif //SFTP_ICONV_DEBUG #ifdef SFTP_HIDE_PARENT_DIR const static char dum_dir=0x00; int isUnderHome(const char* path); #else //SFTP_HIDE_PARENT_DIR # define isUnderHome(a) 1 #endif //SFTP_HIDE_PARENT_DIR #define SFTP_CLIENT_CHARSET "CP932" #define SFTP_SERVER_CHARSET "UTF-8" int client_pathLen(const char* client_path){ // SFTP_CLIENT_CHARSET == "CP932" const unsigned char* p; int r=0; if(!client_path)return 0; for(p=(const char*)client_path;*p;p++)r++; return r; // #error } int server_pathLen(const char* server_path){ // SFTP_SERVER_CHARSET == "UTF-8" const unsigned char* p; int r=0; if(!server_path)return 0; for(p=(const char*)server_path;*p;p++)r++; return r; //#error } int _conv_open(const char* client_path, int flags, mode_t mode) { int r; char* server_path; sftp_putcs("[open:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = open(server_path, flags, mode); sftp_print("[open:end] %s",server_path); g_free(server_path); return r; } int _conv_creat(const char* client_path, mode_t mode) { int r; char* server_path; sftp_putcs("[creat:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = creat(server_path, mode); sftp_print("[creat:end] %s",server_path); g_free(server_path); return r; } int _conv_mkdir(const char* client_path, mode_t mode) { int r; char* server_path; sftp_putcs("[mkdir:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = mkdir(server_path, mode); sftp_print("[mkdir:end] %s",server_path); g_free(server_path); return r; } int _conv_rmdir(const char* client_path) { int r; char* server_path; sftp_putcs("[rmdir:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = rmdir(server_path); sftp_print("[rmdir:end] %s",server_path); g_free(server_path); return r; } int _conv_unlink(const char* client_path) { int r; char* server_path; sftp_putcs("[ulink:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = unlink(server_path); sftp_print("[ulink:end] %s",server_path); g_free(server_path); return r; } int _conv_remove(const char* client_path) { int r; char* server_path; sftp_putcs("[remove:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = remove(server_path); sftp_print("[remove:end] %s",server_path); g_free(server_path); return r; } int _conv_rename(const char* client_path_old, const char* client_path_new) { int r; char* server_path_old, server_path_new; sftp_putcs("[rename:start:old]",client_path_old,client_pathLen (client_path_old)); sftp_putcs("[rename:start:new]",client_path_new,client_pathLen (client_path_new)); server_path_old = g_convert (client_path_old, client_pathLen (client_path_old), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path_old) { errno = ENOMEM; return -1; } server_path_new = (char*)g_convert ((const gchar *)client_path_new, client_pathLen (client_path_new), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path_new) { g_free(server_path_old);errno = ENOMEM; return -1; } r = rename((const char*)server_path_old, (const char*)server_path_new); sftp_print("[rename:end:old] %s",server_path_old); sftp_print("[rename:end;new] %s",server_path_new); g_free(server_path_old); g_free((gchar*)server_path_new); return r; } #ifdef _USE_FILE_OFFSET64 int _conv_stat(const char* client_path, struct stat64* buf) #else int _conv_stat(const char* client_path, struct stat* buf) #endif { int r; char* server_path; sftp_putcs("[stat:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = stat(server_path, buf); sftp_print("[stat:end] %s",server_path); g_free(server_path); return r; } #ifdef _USE_FILE_OFFSET64 int _conv_lstat(const char* client_path, struct stat64* buf) #else int _conv_lstat(const char* client_path, struct stat* buf) #endif { int r; char* server_path; sftp_putcs("[lstat:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = lstat(server_path, buf); sftp_print("[lstat:end] %s",server_path); g_free(server_path); return r; } DIR* _conv_opendir(const char* client_path) { DIR* dir; char* server_path; sftp_putcs("[opendir:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!(int)server_path) { errno = ENOMEM; return -1; } sftp_printInt("[isUnderHome:ret]%d",isUnderHome(server_path)); if(!isUnderHome((const char*)server_path)){ g_free(server_path); return &dum_dir; } dir = opendir(server_path); sftp_print("[opendir:end] %s",server_path); g_free(server_path); return dir; } #ifdef _USE_FILE_OFFSET64 struct dirent64* _conv_readdir(DIR* dir) #else struct dirent* _conv_readdir(DIR* dir) #endif { static struct dirent* d = NULL; struct dirent* r; if(dir==(DIR*)&dum_dir) return NULL; r = readdir(dir); if (r == NULL) return NULL; if (d) free(d); d = malloc(sizeof(struct dirent)+server_pathLen(r->d_name)+1); if (!d) { errno = ENOMEM; return NULL; } memcpy(d, r, sizeof(struct dirent)); sftp_print("[readdir:start] %s",r->d_name); int server_path_len=server_pathLen( r->d_name ); char* client_path; client_path = g_convert (&(r->d_name[0]), server_path_len, SFTP_CLIENT_CHARSET, SFTP_SERVER_CHARSET, NULL, NULL, NULL); if(!client_path) {/* free(d) ;*/ errno = ENOMEM; return NULL; } sftp_putcs("[readdir:end]",client_path,client_pathLen (client_path)); memcpy(&(d->d_name[0]),client_path,server_path_len+1); g_free(client_path); return d; } #ifdef _USE_FILE_OFFSET64 int _conv_closedir(DIR* dir) #else int _conv_closedir(DIR* dir) #endif { if(dir==(DIR*)&dum_dir)return 0; return closedir(dir); } char* _conv_realpath(char* client_path, char resolved_path[]) { char* r; char* server_path; char* server_resolved = malloc(MAXPATHLEN+1); if(!(int)server_resolved) { errno = ENOMEM; return -1; } sftp_putcs("[realpath:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { free(server_resolved);errno = ENOMEM; return -1; } r = realpath(server_path, server_resolved); if (r) { sftp_print("[realpath:mid] %s",server_resolved); int server_resolved_len=server_pathLen( server_resolved ); char* client_path2; client_path2 = g_convert (server_resolved, server_resolved_len, SFTP_CLIENT_CHARSET, SFTP_SERVER_CHARSET, NULL, NULL, NULL); if(!client_path2) { g_free(server_path); free(server_resolved); errno = ENOMEM; resolved_path[0] = NULL; return 0; } sftp_putcs("[realpath:end]",client_path2,client_pathLen (client_path2)); memcpy(resolved_path,client_path2,client_pathLen(client_path2)+1); g_free(client_path2); } else { resolved_path[0] = NULL; } g_free(server_path); free(server_resolved); return r; } int _conv_readlink(const char* client_path, char* buf, size_t bufsiz) { int r; char* server_path; sftp_putcs("[readlink:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = readlink(server_path, buf, bufsiz); sftp_print("[readlink:end] %s",server_path); g_free(server_path); return r; } int _conv_symlink(const char* client_path_old, const char* client_path_new) { int r; char* server_path_old, server_path_new; sftp_putcs("[symlink:start:old]",client_path_old,client_pathLen (client_path_old)); sftp_putcs("[symlink:start:new]",client_path_new,client_pathLen (client_path_new)); server_path_old = g_convert (client_path_old, client_pathLen (client_path_old), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path_old) { errno = ENOMEM; return -1; } server_path_new = g_convert (client_path_new, client_pathLen (client_path_new), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path_new) { g_free(server_path_old); errno = ENOMEM; return -1; } r = symlink(server_path_old, server_path_new); sftp_print("[symlink:end:old] %s",server_path_old); sftp_print("[symlink:end:new] %s",server_path_new); g_free(server_path_old); g_free(server_path_new); return r; } int _conv_chmod(const char* client_path, mode_t mode) { int r; char* server_path; sftp_putcs("[chmod:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = chmod(server_path, mode); sftp_print("[chmod:end] %s",server_path); g_free(server_path); return r; } int _conv_chown(const char* client_path, uid_t owner, gid_t group) { int r; char* server_path; sftp_putcs("[chown:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = chown(server_path, owner, group); sftp_print("[chown:end] %s",server_path); g_free(server_path); return r; } int _conv_lchown(const char* client_path, uid_t owner, gid_t group) { int r; char* server_path; sftp_putcs("[lchown:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = lchown(server_path, owner, group); sftp_print("[lchown:end] %s",server_path); g_free(server_path); return r; } int _conv_utime(const char* client_path, struct utimbuf* buf) { int r; char* server_path; sftp_putcs("[utime:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = utime(server_path, buf); sftp_print("[utime:end] %s",server_path); g_free(server_path); return r; } int _conv_utimes(const char* client_path, struct timeval* tvp) { int r; char* server_path; sftp_putcs("[utimes:start]",client_path,client_pathLen (client_path)); server_path = g_convert (client_path, client_pathLen (client_path), SFTP_SERVER_CHARSET, SFTP_CLIENT_CHARSET, NULL, NULL, NULL); if(!server_path) { errno = ENOMEM; return -1; } r = utimes(server_path, tvp); sftp_print("[utimes:end] %s",server_path); g_free(server_path); return r; } #ifdef open #undef open #endif #ifdef creat #undef creat #endif #ifdef stat #undef stat #endif #ifdef lstat #undef lstat #endif #ifdef readdir #undef readdir #endif #define open _conv_open #define creat _conv_creat #define mkdir _conv_mkdir #define rmdir _conv_rmdir #define unlink _conv_unlink #define rename _conv_rename #define remove(a) _conv_remove(a) #define stat(X, Y) _conv_stat(X, Y) #define lstat(a, b) _conv_lstat(a, b) #define opendir(a) _conv_opendir(a) #define readdir(a) _conv_readdir(a) #define closedir(a) _conv_closedir(a) #define realpath(a, b) _conv_realpath(a, b) #define readlink(a, b, c) _conv_readlink(a, b, c) #define symlink(a, b) _conv_symlink(a, b) #define chmod(a, b) _conv_chmod(a, b) #define chown(a, b, c) _conv_chown(a, b, c) #define lchown(a, b, c) _conv_lchown(a, b, c) #define utime(a, b) _conv_utime(a, b) #define utimes(a, b) _conv_utimes(a, b) #ifdef SFTP_ICONV_DEBUG void sftp_print(const char* string,const char* printpath){ FILE *sftp_file; sftp_file=fopen(DEBUG_FILE,"a+"); if(!sftp_file)return; fprintf(sftp_file,string,printpath); fprintf(sftp_file,"\n"); fclose(sftp_file); return; } void sftp_printInt(const char* string, int i){ FILE *sftp_file; sftp_file=fopen(DEBUG_FILE,"a+"); if(!sftp_file)return; fprintf(sftp_file,string,i); fprintf(sftp_file,"\n"); fclose(sftp_file); return; } void sftp_putcs(const char* string, const char* printpath,int length){ FILE *sftp_file; int i; sftp_file=fopen(DEBUG_FILE,"a+"); if(!sftp_file)return; fprintf(sftp_file,string); for(i=0;i<length;i++) fputc(*printpath++,sftp_file); fprintf(sftp_file,"\n"); fclose(sftp_file); return; } #endif //SFTP_ICONV_DEBUG #ifdef SFTP_HIDE_PARENT_DIR int isUnderHome(const char* path){ char *home= g_get_home_dir(); char *p=path; int i,j; if(!home)return 0; sftp_print("[isUnderHome]%s",home); i=strlen(home); j=strlen(p); if(home[i-2]=='/')i--; if(p[j-2]=='/')j--; if(j<i)return 0; if(memcmp(home,p,i))return 0; if(p[i]==0)return 1; if(p[i]=='/')return 1; return 0; } #endif //SFTP_HIDE_PARENT_DIR
そのあと ./configure し、できた Makefile に glib が利用できるようにする。
122 .c.o: 123 $(CC) $(CFLAGS) $(CPPFLAGS) -c $< 124 +125 sftp-server.cftp-server.o: sftp-server.c +126 $(CC) $(CFLAGS) -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include $(CPPFLAGS) -c $< 127 128 LIBCOMPAT=openbsd-compat/libopenbsd-compat.a 161 sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o -162 $(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) /usr/lib/libglib-2.0.a +162 $(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 163
後は make し、出来上がった sftp-server モジュールを /usr/libへ持っていく
# mv sftp-server sftp-server-new # mv sftp-server-new /usr/lib
最期は、 sshd_config を修正し、新しく作成した sftp-server モジュールを利用するようにする。
- Subsystem sftp /usr/lib/sftp-server + Subsystem sftp /usr/lib/sftp-server-new
あとは、FileZilla や WinSCP からアクセスし、保存したファイルをサーバーにログインしても見られることを確認できれば成功。