diff -r 000000000000 -r 84fdfb0344c9 lm_ssl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lm_ssl.c Sun Feb 01 21:28:57 2009 +0200 @@ -0,0 +1,200 @@ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "lm_types.h" + +/// lm.ssl +/// Object, containing information about ssl abilities for connection. +/// Create, set parameters, and attach to connection with 'ssl' method. + +/// ssl status +/// String, representing what problem have current ssl session. +/// V: no cert found, untrusted cert, cert expired, cert not activated, cert hostname mismatch, cert fingerprint mismatch, generic error +const string2enum_t llm_ssl_status[] = { + { "no cert found", LM_SSL_STATUS_NO_CERT_FOUND }, + { "untrusted cert", LM_SSL_STATUS_UNTRUSTED_CERT }, + { "cert expired", LM_SSL_STATUS_CERT_EXPIRED }, + { "cert not activated", LM_SSL_STATUS_CERT_NOT_ACTIVATED }, + { "cert hostname mismatch", LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH }, + { "cert fingerprint mismatch", LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH }, + { "generic error", LM_SSL_STATUS_GENERIC_ERROR }, + { NULL, 0 }, // XXX +}; + +/// ssl callback function +/// User function, called when ssl error happens. +/// XXX: add lm connection object to args? it is not in API, but can be useful, +/// though, with upvalues it is not required. +/// A: lm ssl object, ssl status +/// R: boolean (false if connection process should be terminated) +LmSSLResponse llm_ssl_callback (LmSSL *ssl, LmSSLStatus status, llm_callback_t *cb) +{ + int ret; + lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference); + llm_ssl_bless (cb->L, ssl); + // XXX lm_ssl_unref (ssl); + luaL_pushenum (cb->L, status, llm_ssl_status); + if (lua_pcall (cb->L, 2, 0, 0)) { + // XXX lua_error (cb->L); + lua_pop (cb->L, 1); + return LM_SSL_RESPONSE_CONTINUE; + } + ret = lua_toboolean (cb->L, -1); + lua_pop (cb->L, 1); + if (ret) + return LM_SSL_RESPONSE_CONTINUE; + else + return LM_SSL_RESPONSE_STOP; +} + +static void string2fingerprint (const char *string, char *buffer) +{ + int i; + for (i = 0; i < 16; i++) { + int h = g_ascii_xdigit_value ((char)string[i*3]); + int l = g_ascii_xdigit_value ((char)string[i*3+1]); + buffer[i] = (char) ((h >= 0 && l >= 0) ? h*16 + l : 0); + } +} + +/// lm.ssl.new +/// Creates new ssl object for use with connection. +/// You can specify server key fingerprint, callback function for error handling, +/// both, or neither. Though, fingerprint should go before callback function. +/// SSL fingerprint is a string like '01:23:45:67:89:AB:CD:EF:FE:DC:BA:98:76:54:32:10'. +/// A: string (optional ssl fingerprint), ssl callback function (optional) +/// R: lm ssl object +static int llm_ssl_new (lua_State *L) +{ + int args = lua_gettop (L); + LmSSL *ssl; + if (args == 0) + ssl = lm_ssl_new (NULL, NULL, NULL, NULL); + else if (args == 1 && !lua_isfunction (L, 1)) { + gchar buffer[16] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + const char *fingerprint = luaL_checkstring (L, 1); + + if (lua_objlen (L, 1) > 46) + string2fingerprint (fingerprint, buffer); + ssl = lm_ssl_new (buffer, NULL, NULL, NULL); + lua_pop (L, 1); + } else { + llm_callback_t *cb; + gchar buffer[16] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + if (args > 1) { + const char *fingerprint = luaL_checkstring (L, 1); + if (lua_objlen (L, 1) > 46) + string2fingerprint (fingerprint, buffer); + luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected"); + } else + luaL_argcheck (L, lua_isfunction (L, 1), 1, "function expected"); + + cb = luaL_malloc (L, sizeof (llm_callback_t)); + cb->reference = luaL_ref (L, LUA_REGISTRYINDEX); + cb->L = L; + + ssl = lm_ssl_new ((args > 1) ? buffer : NULL, (LmSSLFunction)llm_ssl_callback, + cb, (GDestroyNotify)llm_callback_destroy); + lua_pop (L, 1); + } + llm_ssl_bless (L, ssl); + lm_ssl_unref (ssl); // XXX + return 1; +} + +/// lm.ssl.bless +/// Blesses given pointer to lm ssl object. +/// A: lightuserdata (C lm ssl object) +/// R: lm ssl object +static int llm_ssl_bless_lua (lua_State *L) +{ + luaL_argcheck (L, lua_islightuserdata (L, 1), 1, "lm ssl lightuserdata expected"); + llm_ssl_bless (L, lua_touserdata (L, 1)); + lua_remove (L, -2); + return 1; +} + +/// lm.ssl.supported +/// Indicates if SSL is supported by loudmouth library. +/// R: boolean +static int llm_ssl_supported (lua_State *L) +{ + lua_pushboolean (L, lm_ssl_is_supported ()); + return 1; +} + +/// ssl:fingerprint +/// Returns fingerprint of remote server. +/// R: string or nil +static int llm_ssl_fingerprint (lua_State *L) +{ + char buffer[48]; + llm_ssl_t *object = luaL_checklm_ssl (L, 1); + const gchar *fingerprint = lm_ssl_get_fingerprint (object->ssl); + if (fingerprint == NULL) + lua_pushnil (L); + else { + snprintf (buffer, 48, + "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" + "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", + fingerprint[0], fingerprint[1], fingerprint[2], fingerprint[3], + fingerprint[4], fingerprint[5], fingerprint[6], fingerprint[7], + fingerprint[8], fingerprint[9], fingerprint[10], fingerprint[11], + fingerprint[12], fingerprint[13], fingerprint[14], fingerprint[15]); + lua_pushlstring (L, buffer, 47); + } + lua_remove (L, -2); + return 1; +} + +/// ssl:pointer +/// Returns pointer to underlying C structure. +/// R: lightuserdata +static int llm_ssl_pointer (lua_State *L) +{ + llm_ssl_t *object = luaL_checklm_ssl (L, 1); + lua_pushlightuserdata (L, object->ssl); + lua_remove (L, -2); + return 1; +} + +static int llm_ssl_gc (lua_State *L) +{ + llm_ssl_t *object = luaL_checklm_ssl (L, 1); + lm_ssl_unref (object->ssl); + lua_pop (L, 1); + return 0; +} + +const static luaL_Reg llm_ssl_reg_f[] = { + { "new", llm_ssl_new }, + { "bless", llm_ssl_bless_lua }, + { "supported", llm_ssl_supported }, + { NULL, NULL }, +}; + +const static luaL_Reg llm_ssl_reg_m[] = { + { "fingerprint", llm_ssl_fingerprint }, + { "pointer", llm_ssl_pointer }, + { "__gc", llm_ssl_gc }, + { NULL, NULL }, +}; + +int luaopen_lm_ssl (lua_State *L) +{ + luaL_newmetatable (L, "loudmouth.ssl"); + lua_pushstring (L, "__index"); + lua_pushvalue (L, -2); + lua_settable (L, -3); + luaL_register (L, NULL, llm_ssl_reg_m); + lua_pop (L, 1); + luaL_register (L, "lm.ssl", llm_ssl_reg_f); + return 1; +} +