1 /* Copyright 2003-2008 Wang, Chun-Pin All rights reserved. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <syslog.h>
6
7 #include "smbftpd.h"
8
9 extern smbftpd_conf_t smbftpd_conf;
10 extern smbftpd_session_t smbftpd_session;
11
12 #ifdef WITH_ICONV
13 #include <iconv.h>
14
15 static iconv_t codepage2unicode = (iconv_t)-1;
16 static iconv_t unicode2codepage = (iconv_t)-1;
17
18 /**
19 * Initial Unicode convert handler.
20 *
21 * We will open iconv handler of utf8->codepage and codepage->utf8.
22 *
23 * @param encoding The encoding to convert beween utf8 and codepage.
24 *
25 * @return 0: Success
26 * -1: Failed
27 */
smbftpd_unicode_open(const char * encoding)28 int smbftpd_unicode_open(const char *encoding)
29 {
30 if ((iconv_t)-1 != codepage2unicode) {
31 iconv_close(codepage2unicode);
32 codepage2unicode = (iconv_t)-1;
33 }
34 codepage2unicode = iconv_open("UTF-8", encoding);
35 if ((iconv_t)-1 == codepage2unicode) {
36 syslog(LOG_ERR, "%s (%d) Failed to open encoding %s -> UTF-8", __FILE__, __LINE__, encoding);
37 return -1;
38 }
39 if ((iconv_t)-1 != unicode2codepage) {
40 iconv_close(unicode2codepage);
41 unicode2codepage = (iconv_t)-1;
42 }
43 unicode2codepage = iconv_open(encoding, "UTF-8");
44 if ((iconv_t)-1 == unicode2codepage) {
45 syslog(LOG_ERR, "%s (%d) Failed to open encoding UTF-8 -> %s", __FILE__, __LINE__, encoding);
46 return -1;
47 }
48
49 return 0;
50 }
51
52 /**
53 * Close iconv handlers
54 */
smbftpd_unicode_close()55 void smbftpd_unicode_close()
56 {
57 if ((iconv_t)-1 != codepage2unicode) {
58 iconv_close(codepage2unicode);
59 }
60 if ((iconv_t)-1 != unicode2codepage) {
61 iconv_close(unicode2codepage);
62 }
63 codepage2unicode = (iconv_t)-1;
64 unicode2codepage = (iconv_t)-1;
65 }
66
67 /**
68 * Convert string from codepage to UTF-8.
69 *
70 * @param inbuf The string to convert.
71 * @param outbuf The output string. The buffer of output string should be at least
72 * strlen(inbuf) * 4.
73 * @param outlen The length of output buffer length.
74 *
75 * @return 0: Success
76 * -1: Failed
77 */
smbftpd_codepage2unicode(const char * inbuf,char * outbuf,size_t outlen)78 static int smbftpd_codepage2unicode(const char *inbuf, char *outbuf, size_t outlen)
79 {
80 size_t inlen;
81
82 if (!outbuf || !inbuf) {
83 return -1;
84 }
85
86 inlen = strlen(inbuf);
87
88 bzero(outbuf, outlen);
89
90 if (-1 == iconv(codepage2unicode, &inbuf, &inlen, &outbuf, &outlen)) {
91 return -1;
92 }
93
94 return 0;
95 }
96
97 /**
98 * Convert string from UTF-8 to codepage to.
99 *
100 * @param inbuf The string to convert.
101 * @param outbuf The output string. The buffer of output string should be at least
102 * strlen(inbuf) * 4.
103 * @param outlen The length of output buffer length.
104 *
105 * @return 0: Success
106 * -1: Failed
107 */
smbftpd_unicode2codepage(const char * inbuf,char * outbuf,size_t outlen)108 static int smbftpd_unicode2codepage(const char *inbuf, char *outbuf, size_t outlen)
109 {
110 size_t inlen;
111
112 if (!outbuf || !inbuf) {
113 return -1;
114 }
115
116 inlen = strlen(inbuf);
117
118 bzero(outbuf, outlen);
119
120 if (-1 == iconv(unicode2codepage, &inbuf, &inlen, &outbuf, &outlen)) {
121 return -1;
122 }
123
124 return 0;
125 }
126 #endif
127
128 /**
129 * Convert charset from filesystem to client encoding.
130 *
131 * If using utf8 fs, and client is not utf8: utf8->codepage
132 * If not utf8 fs, and client is utf8: codepage->utf8
133 *
134 * Otherwise, just return the pointer of inbuf.
135 *
136 * @param inbuf The string to convert
137 * @param outbuf The buffer for output string
138 * @param outlen The length of outbuf
139 *
140 * @return If convert successfully, return the pointer of outbuf.
141 * If there is no need to convert or conversion failed, return the
142 * pointer of inbuf.
143 */
smbftpd_charset_fs2client(const char * inbuf,char * outbuf,size_t outlen)144 const char *smbftpd_charset_fs2client(const char *inbuf, char *outbuf, size_t outlen)
145 {
146 #ifdef WITH_ICONV
147 if (smbftpd_conf.charset_encoding &&
148 smbftpd_conf.using_utf8_filesystem != smbftpd_session.using_utf8_client) {
149 if (smbftpd_session.using_utf8_client && !smbftpd_conf.using_utf8_filesystem) {
150 if (0 == smbftpd_codepage2unicode(inbuf, outbuf, outlen)) {
151 return outbuf;
152 }
153 } else if (!smbftpd_session.using_utf8_client && smbftpd_conf.using_utf8_filesystem) {
154 if (0 == smbftpd_unicode2codepage(inbuf, outbuf, outlen)) {
155 return outbuf;
156 }
157 }
158 }
159 #endif
160
161 return inbuf;
162 }
163
164 /**
165 * Convert client encoding to filesystem encoding.
166 *
167 * If client is using UTF-8, and filesystem is not: utf8->codepage
168 * If client is not using UTF-8, and filesystem is: codepage->utf8
169 *
170 * If no need to convert, just return NULL.
171 *
172 * @param inbuf The string to convert.
173 *
174 * @return NULL if no need to convert or conversion failed.
175 * malloc() a new string buffer for the converted string. caller should
176 * free() the returned buffer.
177 */
smbftpd_charset_client2fs(const char * inbuf)178 char *smbftpd_charset_client2fs(const char *inbuf)
179 {
180 #ifdef WITH_ICONV
181 char *outbuf = NULL;
182 size_t outlen;
183
184 if (smbftpd_conf.charset_encoding &&
185 smbftpd_conf.using_utf8_filesystem != smbftpd_session.using_utf8_client) {
186 if (smbftpd_session.using_utf8_client && !smbftpd_conf.using_utf8_filesystem) {
187 outlen = strlen(inbuf) + 1;
188 outbuf = calloc(outlen, 1);
189 if (0 == smbftpd_unicode2codepage(inbuf, outbuf, outlen)) {
190 return outbuf;
191 }
192 } else if (!smbftpd_session.using_utf8_client && smbftpd_conf.using_utf8_filesystem) {
193 outlen = strlen(inbuf) * 6 + 1;
194 outbuf = calloc(outlen, 1);
195 if (0 == smbftpd_codepage2unicode(inbuf, outbuf, outlen)) {
196 return outbuf;
197 }
198 }
199 }
200
201 if (outbuf) {
202 free(outbuf);
203 }
204 #endif
205
206 return NULL;
207 }
208
209
210