util-src/encodings.c

1
/* Prosody IM
2
-- Copyright (C) 2008-2010 Matthew Wild
3
-- Copyright (C) 2008-2010 Waqas Hussain
4
-- 
5
-- This project is MIT/X11 licensed. Please see the
6
-- COPYING file in the source package for more information.
7
--
8
*/
9
 
10
/*
11
* encodings.c
12
* Lua library for base64, stringprep and idna encodings
13
*/
14
 
15
/* Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way */
16
#define _CRT_SECURE_NO_DEPRECATE
17
 
18
#include <string.h>
19
#include <stdlib.h>
20
#include "lua.h"
21
#include "lauxlib.h"
22
 
23
/***************** BASE64 *****************/
24
 
25
static const char code[]=
26
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27
 
28
static void base64_encode(luaL_Buffer *b, unsigned int c1, unsigned int c2, unsigned int c3, int n)
29
{
30
	unsigned long tuple=c3+256UL*(c2+256UL*c1);
31
	int i;
32
	char s[4];
33
	for (i=0; i<4; i++) {
34
		s[3-i] = code[tuple % 64];
35
		tuple /= 64;
36
	}
37
	for (i=n+1; i<4; i++) s[i]='=';
38
	luaL_addlstring(b,s,4);
39
}
40
 
41
static int Lbase64_encode(lua_State *L)		/** encode(s) */
42
{
43
	size_t l;
44
	const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l);
45
	luaL_Buffer b;
46
	int n;
47
	luaL_buffinit(L,&b);
48
	for (n=l/3; n--; s+=3) base64_encode(&b,s[0],s[1],s[2],3);
49
	switch (l%3)
50
	{
51
		case 1: base64_encode(&b,s[0],0,0,1);		break;
52
		case 2: base64_encode(&b,s[0],s[1],0,2);		break;
53
	}
54
	luaL_pushresult(&b);
55
	return 1;
56
}
57
 
58
static void base64_decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int n)
59
{
60
	unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1));
61
	char s[3];
62
	switch (--n)
63
	{
64
		case 3: s[2]=(char) tuple;
65
		case 2: s[1]=(char) (tuple >> 8);
66
		case 1: s[0]=(char) (tuple >> 16);
67
	}
68
	luaL_addlstring(b,s,n);
69
}
70
 
71
static int Lbase64_decode(lua_State *L)		/** decode(s) */
72
{
73
	size_t l;
74
	const char *s=luaL_checklstring(L,1,&l);
75
	luaL_Buffer b;
76
	int n=0;
77
	char t[4];
78
	luaL_buffinit(L,&b);
79
	for (;;)
80
	{
81
		int c=*s++;
82
		switch (c)
83
		{
84
			const char *p;
85
			default:
86
				p=strchr(code,c); if (p==NULL) return 0;
87
				t[n++]= (char) (p-code);
88
				if (n==4)
89
				{
90
					base64_decode(&b,t[0],t[1],t[2],t[3],4);
91
					n=0;
92
				}
93
				break;
94
			case '=':
95
				switch (n)
96
				{
97
					case 1: base64_decode(&b,t[0],0,0,0,1);		break;
98
					case 2: base64_decode(&b,t[0],t[1],0,0,2);	break;
99
					case 3: base64_decode(&b,t[0],t[1],t[2],0,3);	break;
100
				}
101
				n=0;
102
				break;
103
			case 0:
104
				luaL_pushresult(&b);
105
				return 1;
106
			case '\n': case '\r': case '\t': case ' ': case '\f': case '\b':
107
				break;
108
		}
109
	}
110
}
111
 
112
static const luaL_Reg Reg_base64[] =
113
{
114
	{ "encode",	Lbase64_encode	},
115
	{ "decode",	Lbase64_decode	},
116
	{ NULL,		NULL	}
117
};
118
 
119
/***************** STRINGPREP *****************/
120
#ifndef USE_STRINGPREP_ICU
121
/****************** libidn ********************/
122
 
123
#include <stringprep.h>
124
 
125
static int stringprep_prep(lua_State *L, const Stringprep_profile *profile)
126
{
127
	size_t len;
128
	const char *s;
129
	char string[1024];
130
	int ret;
131
	if(!lua_isstring(L, 1)) {
132
		lua_pushnil(L);
133
		return 1;
134
	}
135
	s = lua_tolstring(L, 1, &len);
136
	if (len >= 1024) {
137
		lua_pushnil(L);
138
		return 1; /* TODO return error message */
139
	}
140
	strcpy(string, s);
141
	ret = stringprep(string, 1024, (Stringprep_profile_flags)0, profile);
142
	if (ret == STRINGPREP_OK) {
143
		lua_pushstring(L, string);
144
		return 1;
145
	} else {
146
		lua_pushnil(L);
147
		return 1; /* TODO return error message */
148
	}
149
}
150
 
151
#define MAKE_PREP_FUNC(myFunc, prep) \
152
static int myFunc(lua_State *L) { return stringprep_prep(L, prep); }
153
 
154
MAKE_PREP_FUNC(Lstringprep_nameprep, stringprep_nameprep)		/** stringprep.nameprep(s) */
155
MAKE_PREP_FUNC(Lstringprep_nodeprep, stringprep_xmpp_nodeprep)		/** stringprep.nodeprep(s) */
156
MAKE_PREP_FUNC(Lstringprep_resourceprep, stringprep_xmpp_resourceprep)		/** stringprep.resourceprep(s) */
157
MAKE_PREP_FUNC(Lstringprep_saslprep, stringprep_saslprep)		/** stringprep.saslprep(s) */
158
 
159
static const luaL_Reg Reg_stringprep[] =
160
{
161
	{ "nameprep",	Lstringprep_nameprep	},
162
	{ "nodeprep",	Lstringprep_nodeprep	},
163
	{ "resourceprep",	Lstringprep_resourceprep	},
164
	{ "saslprep",	Lstringprep_saslprep	},
165
	{ NULL,		NULL	}
166
};
167
 
168
#else
169
#include <unicode/usprep.h>
170
#include <unicode/ustring.h>
171
#include <unicode/utrace.h>
172
 
173
static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile)
174
{
175
	size_t input_len;
176
	int32_t unprepped_len, prepped_len, output_len;
177
	const char *input;
178
	char output[1024];
179
 
180
	UChar unprepped[1024]; /* Temporary unicode buffer (1024 characters) */
181
	UChar prepped[1024];
182
	
183
	UErrorCode err = U_ZERO_ERROR;
184
 
185
	if(!lua_isstring(L, 1)) {
186
		lua_pushnil(L);
187
		return 1;
188
	}
189
	input = lua_tolstring(L, 1, &input_len);
190
	if (input_len >= 1024) {
191
		lua_pushnil(L);
192
		return 1;
193
	}
194
	u_strFromUTF8(unprepped, 1024, &unprepped_len, input, input_len, &err);
195
	prepped_len = usprep_prepare(profile, unprepped, unprepped_len, prepped, 1024, 0, NULL, &err);
196
	if (U_FAILURE(err)) {
197
		lua_pushnil(L);
198
		return 1;
199
	} else {
200
		u_strToUTF8(output, 1024, &output_len, prepped, prepped_len, &err);
201
		if(output_len < 1024)
202
			lua_pushlstring(L, output, output_len);
203
		else
204
			lua_pushnil(L);
205
		return 1;
206
	}
207
}
208
 
209
UStringPrepProfile *icu_nameprep;
210
UStringPrepProfile *icu_nodeprep;
211
UStringPrepProfile *icu_resourceprep; 
212
UStringPrepProfile *icu_saslprep;
213
 
214
/* initialize global ICU stringprep profiles */
215
void init_icu()
216
{
217
	UErrorCode err = U_ZERO_ERROR;
218
	utrace_setLevel(UTRACE_VERBOSE);
219
	icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err);
220
	icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err);
221
	icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err);
222
	icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err);
223
	if (U_FAILURE(err)) fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err));
224
}
225
 
226
#define MAKE_PREP_FUNC(myFunc, prep) \
227
static int myFunc(lua_State *L) { return icu_stringprep_prep(L, prep); }
228
 
229
MAKE_PREP_FUNC(Lstringprep_nameprep, icu_nameprep)		/** stringprep.nameprep(s) */
230
MAKE_PREP_FUNC(Lstringprep_nodeprep, icu_nodeprep)		/** stringprep.nodeprep(s) */
231
MAKE_PREP_FUNC(Lstringprep_resourceprep, icu_resourceprep)		/** stringprep.resourceprep(s) */
232
MAKE_PREP_FUNC(Lstringprep_saslprep, icu_saslprep)		/** stringprep.saslprep(s) */
233
 
234
static const luaL_Reg Reg_stringprep[] =
235
{
236
	{ "nameprep",	Lstringprep_nameprep	},
237
	{ "nodeprep",	Lstringprep_nodeprep	},
238
	{ "resourceprep",	Lstringprep_resourceprep	},
239
	{ "saslprep",	Lstringprep_saslprep	},
240
	{ NULL,		NULL	}
241
};
242
#endif
243
 
244
/***************** IDNA *****************/
245
#ifndef USE_STRINGPREP_ICU
246
/****************** libidn ********************/
247
 
248
#include <idna.h>
249
#include <idn-free.h>
250
 
251
static int Lidna_to_ascii(lua_State *L)		/** idna.to_ascii(s) */
252
{
253
	size_t len;
254
	const char *s = luaL_checklstring(L, 1, &len);
255
	char* output = NULL;
256
	int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES);
257
	if (ret == IDNA_SUCCESS) {
258
		lua_pushstring(L, output);
259
		idn_free(output);
260
		return 1;
261
	} else {
262
		lua_pushnil(L);
263
		idn_free(output);
264
		return 1; /* TODO return error message */
265
	}
266
}
267
 
268
static int Lidna_to_unicode(lua_State *L)		/** idna.to_unicode(s) */
269
{
270
	size_t len;
271
	const char *s = luaL_checklstring(L, 1, &len);
272
	char* output = NULL;
273
	int ret = idna_to_unicode_8z8z(s, &output, 0);
274
	if (ret == IDNA_SUCCESS) {
275
		lua_pushstring(L, output);
276
		idn_free(output);
277
		return 1;
278
	} else {
279
		lua_pushnil(L);
280
		idn_free(output);
281
		return 1; /* TODO return error message */
282
	}
283
}
284
#else
285
#include <unicode/ustdio.h>
286
#include <unicode/uidna.h>
287
/* IDNA2003 or IDNA2008 ? ? ? */
288
static int Lidna_to_ascii(lua_State *L)		/** idna.to_ascii(s) */
289
{
290
	size_t len;
291
	int32_t ulen, dest_len, output_len;
292
	const char *s = luaL_checklstring(L, 1, &len);
293
	UChar ustr[1024];
294
	UErrorCode err = U_ZERO_ERROR;
295
	UChar dest[1024];
296
	char output[1024];
297
 
298
	u_strFromUTF8(ustr, 1024, &ulen, s, len, &err);
299
	dest_len = uidna_IDNToASCII(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err);
300
	if (U_FAILURE(err)) {
301
		lua_pushnil(L);
302
		return 1;
303
	} else {
304
		u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err);
305
		if(output_len < 1024)
306
			lua_pushlstring(L, output, output_len);
307
		else
308
			lua_pushnil(L);
309
		return 1;
310
	}
311
}
312
 
313
static int Lidna_to_unicode(lua_State *L)		/** idna.to_unicode(s) */
314
{
315
	size_t len;
316
	int32_t ulen, dest_len, output_len;
317
	const char *s = luaL_checklstring(L, 1, &len);
318
	UChar* ustr;
319
	UErrorCode err = U_ZERO_ERROR;
320
	UChar dest[1024];
321
	char output[1024];
322
 
323
	u_strFromUTF8(ustr, 1024, &ulen, s, len, &err);
324
	dest_len = uidna_IDNToUnicode(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err);
325
	if (U_FAILURE(err)) {
326
		lua_pushnil(L);
327
		return 1;
328
	} else {
329
		u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err);
330
		if(output_len < 1024)
331
			lua_pushlstring(L, output, output_len);
332
		else
333
			lua_pushnil(L);
334
		return 1;
335
	}
336
}
337
#endif
338
 
339
static const luaL_Reg Reg_idna[] =
340
{
341
	{ "to_ascii",	Lidna_to_ascii	},
342
	{ "to_unicode",	Lidna_to_unicode	},
343
	{ NULL,		NULL	}
344
};
345
 
346
/***************** end *****************/
347
 
348
static const luaL_Reg Reg[] =
349
{
350
	{ NULL,		NULL	}
351
};
352
 
353
LUALIB_API int luaopen_util_encodings(lua_State *L)
354
{
355
#ifdef USE_STRINGPREP_ICU
356
	init_icu();
357
#endif
358
	luaL_register(L, "encodings", Reg);
359
 
360
	lua_pushliteral(L, "base64");
361
	lua_newtable(L);
362
	luaL_register(L, NULL, Reg_base64);
363
	lua_settable(L,-3);
364
 
365
	lua_pushliteral(L, "stringprep");
366
	lua_newtable(L);
367
	luaL_register(L, NULL, Reg_stringprep);
368
	lua_settable(L,-3);
369
 
370
	lua_pushliteral(L, "idna");
371
	lua_newtable(L);
372
	luaL_register(L, NULL, Reg_idna);
373
	lua_settable(L,-3);
374
 
375
	lua_pushliteral(L, "version");			/** version */
376
	lua_pushliteral(L, "-3.14");
377
	lua_settable(L,-3);
378
	return 1;
379
}