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