From 4b2919c207a4bee259698c13cbb7aace0e45c942 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Sun, 25 Jul 2004 21:27:56 +0000 Subject: [PATCH] * src/tls/: Library for TLS support (not completed) * src/ejabberd_auth.erl: Now uses two LDAP connections * src/ejabberd_c2s.erl: Return resource on get_presence request (thanks to Mickael Remond) * src/mod_configure2.erl: Bugfix (thanks to Sergei Golovan) * src/msgs/ua.msg: New Ukrainian translation (thanks to usercard) * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) SVN Revision: 247 --- ChangeLog | 17 +++ src/ejabberd.hrl | 2 +- src/ejabberd_auth.erl | 5 +- src/ejabberd_c2s.erl | 3 +- src/mod_configure2.erl | 2 +- src/msgs/ua.msg | 250 +++++++++++++++++++++++++++++++++++++++++ src/tls/tls.erl | 138 +++++++++++++++++++++++ src/tls/tls_drv.c | 188 +++++++++++++++++++++++++++++++ 8 files changed, 600 insertions(+), 5 deletions(-) create mode 100644 src/msgs/ua.msg create mode 100644 src/tls/tls.erl create mode 100644 src/tls/tls_drv.c diff --git a/ChangeLog b/ChangeLog index 2ae320d3b..2e5465fb5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,26 @@ +2004-07-25 Alexey Shchepin + + * src/tls/: Library for TLS support (not completed) + + * src/ejabberd_auth.erl: Now uses two LDAP connections + + * src/ejabberd_c2s.erl: Return resource on get_presence request + (thanks to Mickael Remond) + + * src/mod_configure2.erl: Bugfix (thanks to Sergei Golovan) + + * src/msgs/ua.msg: New Ukrainian translation (thanks to usercard) + + * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) + 2004-07-23 Alexey Shchepin * src/eldap/eldap.erl: Bugfix 2004-07-13 Alexey Shchepin + * (all): ejabberd-0.7 released + * src/web/ejabberd_web_admin.erl: Better i18n support (thanks to Sergei Golovan) diff --git a/src/ejabberd.hrl b/src/ejabberd.hrl index 5a6d391f9..249818d60 100644 --- a/src/ejabberd.hrl +++ b/src/ejabberd.hrl @@ -6,7 +6,7 @@ %%% Id : $Id$ %%%---------------------------------------------------------------------- --define(VERSION, "0.6-alpha"). +-define(VERSION, "0.8-alpha"). %-define(ejabberd_debug, true). %-define(DBGFSM, true). diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index fc239680b..c697e8b73 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -70,7 +70,8 @@ init([]) -> ok; ldap -> LDAPServers = ejabberd_config:get_local_option(ldap_servers), - eldap:start_link("ejabberd", LDAPServers, 389, "", "") + eldap:start_link("ejabberd", LDAPServers, 389, "", ""), + eldap:start_link("ejabberd_bind", LDAPServers, 389, "", "") end, {ok, #state{}}. @@ -326,7 +327,7 @@ check_password_ldap(User, Password) -> false -> false; DN -> - case eldap:bind("ejabberd", DN, Password) of + case eldap:bind("ejabberd_bind", DN, Password) of ok -> true; _ -> diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 8b10d064d..25de839e9 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -686,8 +686,9 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> Show = get_showtag(PresLast), Status = get_statustag(PresLast), + Resource = StateData#state.resource, - Reply = {User, Show, Status}, + Reply = {User, Resource, Show, Status}, {reply, Reply, StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 58eb387a4..d22d344e4 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -135,7 +135,7 @@ process_get({xmlelement, "access", Attrs, _SubEls}) -> {result, {xmlelement, "access", Attrs, [{xmlcdata, Str}]}}; process_get({xmlelement, "last", Attrs, _SubEls}) -> case catch mnesia:dirty_select( - last_activity, [{{last_activity, '_', '$1'}, [], ['$1']}]) of + last_activity, [{{last_activity, '_', '$1', '_'}, [], ['$1']}]) of {'EXIT', _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; Vals -> diff --git a/src/msgs/ua.msg b/src/msgs/ua.msg new file mode 100644 index 000000000..283707184 --- /dev/null +++ b/src/msgs/ua.msg @@ -0,0 +1,250 @@ +% $Id$ + +% mod_configure.erl +{"DB Tables Configuration at ", "Конфігурація таблиць БД на "}. +{"Choose storage type of tables", "Оберіть тип збереження таблиць"}. +{"RAM copy", "ОЗУ"}. +{"RAM and disc copy", "ОЗУ та диск"}. +{"Disc only copy", "тільки диск"}. +{"Remote copy", "не зберігаеться локально"}. +{"Stop Modules at ", "Зупинка модулів на "}. +{"Choose modules to stop", "Оберіть модулі, які необхідно зупинити"}. +{"Start Modules at ", "Запуск модулів на "}. +{"Enter list of {Module, [Options]}", "Введіть список такого виду {Module, [Options]}"}. +{"List of modules to start", "Список завантажуваних модулів"}. +{"Backup to File at ", "Резервне копіювання в файл на "}. +{"Enter path to backup file", "Введіть шлях до резервного файла"}. +{"Path to File", "Шлях до файла"}. +{"Restore Backup from File at ", "Відновлення з резервної копії на "}. +{"Dump Backup to Text File at ", "Копіювання в текстовий файл на "}. +{"Enter path to text file", "Введіть шлях до текстового файла"}. +{"Import User from File at ", "Імпортування користувача з файла на "}. +{"Enter path to jabberd1.4 spool file", "Введіть шлях до файла зі спула jabberd1.4"}. +{"Import Users from Dir at ", "Імпортування користувача з директорії на "}. +{"Enter path to jabberd1.4 spool dir", "Введіть шлях до директорії спула jabberd1.4"}. +{"Path to Dir", "шлях до директорії"}. +{"Hostname Configuration", "Конфігурація назви хоста"}. +{"Choose host name", "Оберіть назву хоста"}. +{"Host name", "Назва хоста"}. +{"Access Control List Configuration", "Конфігурація списків управління доступом"}. +{"Access control lists", "Списки управління доступом"}. +{"Access Configuration", "Конфігурація доступа"}. +{"Access rules", "Правила доступу"}. +{"Remove Users", "Видалення користувачів"}. +{"Choose users to remove", "Оберіть користувачів, яких необхідно видалити"}. +{"Administration of ", "Адміністрування "}. +{"Action on user", "Дія над користувачем"}. +{"Edit Properties", "Змінити параметри"}. +{"Remove User", "Видалити коростувача"}. + +% mod_disco.erl +{"Configuration", "Конфігурація"}. +{"Online Users", "Підключені користувачі"}. +{"All Users", "Всі коритстувачі"}. +{"Outgoing S2S connections", "Вихідні S2S-з`єднання"}. +{"To ~s", "До ~s"}. +{"From ~s", "Від ~s"}. +{"Running Nodes", "Рабочі вузли"}. +{"Stopped Nodes", "Зупинені вузли"}. +{"Host Name", "Назва хоста"}. +{"Access Control Lists", "Списки управління доступом"}. +{"Access Rules", "Правила доступу"}. +{"Remove Users", "Видалення користувачів"}. +{"DB", "БД"}. +{"Modules", "Модулі"}. +{"Start Modules", "Запуск модулів"}. +{"Stop Modules", "Зупинка модулів"}. +{"Backup Management", "Управління резервним копіюванням"}. +{"Import users from jabberd1.4 spool files", "Імпортування користувачів зі спулу jabberd1.4"}. +{"Backup", "Резервне копіювання"}. +{"Restore", "Відновлення з резервної копії"}. +{"Dump to Text File", "Копіювання в текстовий файл"}. +{"Import File", "Імпорт з файла"}. +{"Import Directory", "Імпорт з директорії"}. + +% mod_register.erl +{"Choose a username and password to register with this server", + "Оберіь назву користувача та пароль для реєстрації на цьому сервері"}. + +% mod_vcard.erl +{"Erlang Jabber Server\nCopyright (c) 2002-2004 Alexey Shchepin", + "Erlang Jabber Server\nCopyright (c) 2002-2004 Алексей Щепин"}. +{"ejabberd vCard module\nCopyright (c) 2003-2004 Alexey Shchepin", + "ejabberd vCard модуль\nCopyright (c) 2003-2004 Алексей Щепин"}. +{"You need an x:data capable client to search", + "Для пошуку необхідний x:data-сумісний кліент"}. +{"Search users in ", "Пошук користувачів в "}. +{"Fill in fields to search for any matching Jabber User", + "Заповніть поля для пошуку користувача Jabber"}. +{"Results of search in ", "Результати пошуку в "}. + +{"User", "Користувач"}. +{"Full Name", "Повне ім`я"}. +{"Name", "Ім`я"}. +{"Middle Name", "По-батькові"}. +{"Family Name", "Фамілія"}. +{"Nickname", "Псевдонім"}. +{"Birthday", "День нарождення"}. +{"Country", "Країна"}. +{"City", "Місто"}. +{"email", "email"}. +{"Organization Name", "Назва организації"}. +{"Organization Unit", "Відділ организації"}. + +% mod_pubsub/mod_pubsub.erl +{"ejabberd pub/sub module\nCopyright (c) 2003-2004 Alexey Shchepin", + "ejabberd pub/sub модуль\nCopyright (c) 2003-2004 Алексей Щепин"}. + +% mod_muc/mod_muc.erl +{"You need an x:data capable client to register nickname", + "Для реєстрації псевдоніму необхідний x:data-сумісний кліент"}. +{"Nickname Registration at ", "Реєстрація псевдоніма на "}. +{"Enter nickname you want to register", "Введіть псевдонім, який ви хочете зареєструвати"}. +{"ejabberd MUC module\nCopyright (c) 2003-2004 Alexey Shchepin", + "ejabberd MUC модуль\nCopyright (c) 2003-2004 Алексей Щепин"}. +{"Only service administrators are allowed to send service messages", + "Тільки адміністратор сервісу може надсилати службові повідомлення"}. +{"Room creation is not allowed by service policy", + "Створювати конференцію не дозволяється політикою сервіса"}. +{"Conference room does not exist", "Конференція не існує"}. +{"Access denied by service policy", "Доступ зоборонений політикою сервіса"}. +{"You must fill in field \"nick\" in the form", + "Вам необхідно заповнити поле \"nick\" у формі"}. +{"Specified nickname is already registered", "Вказаний псевдонім вже зареєстрований"}. + +% mod_muc/mod_muc_room.erl +{" has set the subject to: ", " встановив(ла) тему: "}. +{"You need an x:data capable client to configure room", + "Для конфігурування кімнати необхідний x:data-сумісний кліент"}. +{"Configuration for ", "Конфігурація "}. +{"Room title", "Назва кімнати"}. +{"Allow users to change subject?", "Дозволити користувачам змінювати тему?"}. +{"Allow users to query other users?", + "Дозволити iq-запити до користувачів?"}. +{"Allow users to send private messages?", + "Дозволити приватні повідомлення?"}. +{"Make room public searchable?", "Зробити кімнату видимою всім?"}. +{"Make participants list public?", "Зробити список участників видимим всім?"}. +{"Make room persistent?", "Зробити кімнату постійною?"}. +{"Make room moderated?", "Зробити кімнату модерованою?"}. +{"Default users as members?", + "Зробити користувачів участниками за замовчуванням?"}. +{"Make room members only?", + "Кімната тільки для зареєтрованых участників?"}. +{"Allow users to send invites?", + "Дозволити користувачам посилати запрошення?"}. +{"Make room password protected?", "Зробити кімнату захищеною паролем?"}. +{"Password", "Пароль"}. +{"Make room anonymous?", "Зробити кімнату анонімною?"}. +{"Enable logging?", "Включити журнал роботи?"}. +{"Only moderators and participants are allowed to change subject in this room", + "Тільки модератори та участники можуть змінювати тему в цій комнаті"}. +{"Only moderators are allowed to change subject in this room", + "Тільки модератори можуть змінювати тему в цій комнаті"}. +{"Visitors are not allowed to send messages to all occupants", + "Відвідувачам не дозволяється посилати повідомлення всім присутнім"}. +{"Only occupants are allowed to send messages to the conference", + "Тільки присутнім дозволяється посилати повідомленняя в конференцію"}. +{"It is not allowed to send normal messages to the conference", + "Не дозволяється посилати звичайні повідомленняя в конференцію"}. +{"It is not allowed to send private messages to the conference", + "Не дозволяється посилати приватні повідомлення в конференцію"}. +{"Improper message type", "Неправильний тип повідомлення"}. +{"Nickname is already in use by another occupant", "Псевдонім зайнятий кимось з присутніх"}. +{"Nickname is registered by another person", "Псевдонім зайнятий кимось іншим"}. +{"It is not allowed to send private messages of type \"groupchat\"", + "Не дозволяється посилати приватні повідомлення типу \"groupchat\""}. +{"Recipient is not in the conference room", "Адресата немає в конференції"}. +{"Only occupants are allowed to send queries to the conference", + "Тільки присутнім дозволяється відправляти запити в конференцію"}. +{"Queries to the conference members are not allowed in this room", + "Запити до користувачів в цій конференції зоборонені"}. +{"You have been banned from this room", "Вам заборонено входити в цю конференцію"}. +{"Membership required to enter this room", "В цю конференціию можуть входити тільки її члени"}. +{"Password required to enter this room", "Щоб зайти в цю конференцію, необхідний пароль"}. +{"Incorrect password", "Неправильний пароль"}. +{"Administrator privileges required", "Необхідні права адміністратора"}. +{"Moderator privileges required", "Необхідні права модератора"}. +{"JID ~s is invalid", "JID ~s недопустимий"}. +{"Nickname ~s does not exist in the room", "Псевдонім ~s в кімнаті відсутній"}. +{"Invalid affiliation: ~s", "Недопустимий ранг: ~s"}. +{"Invalid role: ~s", "Недопустима роль: ~s"}. +{"Owner privileges required", "Необхідні права власника"}. +{"private, ", "приватна, "}. + +% mod_irc/mod_irc.erl +{"ejabberd IRC module\nCopyright (c) 2003-2004 Alexey Shchepin", + "ejabberd IRC модуль\nCopyright (c) 2003-2004 Алексей Щепин"}. +{"You need an x:data capable client to configure mod_irc settings", + "Для налагодження параметрів mod_irc необхідний x:data-сумісний кліент"}. +{"Registration in mod_irc for ", "Реєстрація в mod_irc для "}. +{"Enter username and encodings you wish to use for connecting to IRC servers", + "Введіть ім`я користувача та кодування, які будуть використовуватися при підключенні до IRC-серверів"}. +{"IRC Username", "Ім`я користувача IRC"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Щоб вказати різні кодування для різних серверів IRC, заповніть список значеннями в форматі '{\"irc server\", \"encoding\"}'. За замовчуванням ця служба використовує кодування \"~s\"."}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Приклад: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Encodings", "Кодування"}. + +% web/ejabberd_web_admin.erl +{"ejabberd administration", "Адміністрування ejabberd"}. +{"Users", "Користувачі"}. +{"Nodes", "Вузли"}. +{"Statistics", "Статистика"}. +{"ejabberd (c) 2002-2004 Alexey Shchepin", "ejabberd (c) 2002-2004 Алексей Щепин"}. +{"(raw)", "(необроблений формат)"}. +{"submitted", "відправлено"}. +{"bad format", "неправильний формат"}. +{"raw", "необроблений формат"}. +{"ejabberd access control lists configuration", "Конфігурація списків управління доступом ejabberd"}. +{"Delete Selected", "Видалити виділені"}. +{"Submit", "Відправити"}. +{"ejabberd access rules configuration", "Конфігурація правил доступу ejabberd"}. +{"~s access rule configuration", "Конфігурація правила доступу ~s"}. +{"ejabberd users", "Користувачі ejabberd"}. +{"ejabberd stats", "Статистика ejabberd"}. +{"Node not found", "Вузол не знайдено"}. +{"Add New", "Добавити"}. +{"Registered users", "Зареєстровані користувачі"}. +{"Authentificated users", "Аутентифіковані користувачі"}. +{"Online users", "Підключені користувачі"}. +{"Outgoing S2S servers", "Вихідні S2S-сервери"}. +{"Change Password", "Змінити пароль"}. +{"Connected Resources:", "Підключені ресурси:"}. +{"Password:", "Пароль:"}. +{"None", "Ні"}. +{"Node ", "Вузол "}. +{"DB Management", "Управління БД"}. +{"Listened Ports Management", "Управління відкритими портами"}. +{"Restart", "Перезапустити"}. +{"Stop", "Зупинити"}. +{"RPC call error", "Помилка визову RPC"}. +{"DB Tables at ", "Таблиці БД на "}. +{"Name", "Назва"}. +{"Storage Type", "Тип таблиці"}. +{"Size", "Розмір"}. +{"Memory", "Пам`ять"}. +{"Backup Management at ", "Управління резервним копіюванням на "}. +{"Store a backup in a file", "Зберігти резервну копію в файл"}. +{"OK", "Продовжити"}. +{"Restore a backup from a file", "Відновити резервну копію з файла"}. +{"Install a database fallback from a file", "Встановити базу даних для відновлення при слідуючому запуску"}. +{"Dump a database in a text file", "Копіювати базу даних в текстовий файл"}. +{"Restore a database from a text file", "Відновити базу даних з текстового файла"}. +{"Listened Ports at ", "Відкриті порти на "}. +{"~p statistics", "статистика вузла ~p"}. +{"Uptime", "Час роботи сервера"}. +{"CPU Time", "Процесорний час"}. +{"Transactions commited", "Транзакції завершені"}. +{"Transactions aborted", "Транзакції відмінені"}. +{"Transactions restarted", "Транзакції перезапущені"}. +{"Transactions logged", "Транзакції запротокольовані"}. +{"Port", "Порт"}. +{"Module", "Модуль"}. +{"Options", "Параметри"}. +{"Update", "Обновити"}. +{"Delete", "Видалити"}. +{"", ""}. + +% Local Variables: +% mode: erlang +% End: \ No newline at end of file diff --git a/src/tls/tls.erl b/src/tls/tls.erl new file mode 100644 index 000000000..d444bb7ee --- /dev/null +++ b/src/tls/tls.erl @@ -0,0 +1,138 @@ +%%%---------------------------------------------------------------------- +%%% File : tls.erl +%%% Author : Alexey Shchepin +%%% Purpose : Interface to openssl +%%% Created : 24 Jul 2004 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(tls). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +-behaviour(gen_server). + +-export([start/0, start_link/0, convert/3, test/0]). + +%% Internal exports, call-back functions. +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3, + terminate/2]). + +-define(SET_CERTIFICATE_FILE, 1). +-define(SET_ENCRYPTED_INPUT, 2). +-define(SET_DECRYPTED_OUTPUT, 3). +-define(GET_ENCRYPTED_OUTPUT, 4). +-define(GET_DECRYPTED_INPUT, 5). + +-define(DECRYPTED_INPUT, 1). +-define(ENCRYPTED_OUTPUT, 2). + + +start() -> + gen_server:start({local, ?MODULE}, ?MODULE, [], []). + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +init([]) -> + ok = erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv), + Port = open_port({spawn, tls_drv}, [binary]), + Res = port_control(Port, ?SET_CERTIFICATE_FILE, "./ssl.pem" ++ [0]), + case Res of + [0] -> + %ets:new(iconv_table, [set, public, named_table]), + %ets:insert(iconv_table, {port, Port}), + {ok, Port}; + [1 | Error] -> + {error, Error} + end. + + +%%% -------------------------------------------------------- +%%% The call-back functions. +%%% -------------------------------------------------------- + +handle_call(_, _, State) -> + {noreply, State}. + +handle_cast(_, State) -> + {noreply, State}. + +handle_info({'EXIT', Pid, Reason}, Port) -> + {noreply, Port}; + +handle_info({'EXIT', Port, Reason}, Port) -> + {stop, {port_died, Reason}, Port}; +handle_info(_, State) -> + {noreply, State}. + +code_change(OldVsn, State, Extra) -> + {ok, State}. + +terminate(_Reason, Port) -> + Port ! {self, close}, + ok. + + + +convert(From, To, String) -> + [{port, Port} | _] = ets:lookup(iconv_table, port), + Bin = term_to_binary({From, To, String}), + BRes = port_control(Port, 1, Bin), + binary_to_list(BRes). + + +test() -> + ok = erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv), + Port = open_port({spawn, tls_drv}, [binary]), + io:format("open_port: ~p~n", [Port]), + PCRes = port_control(Port, ?SET_CERTIFICATE_FILE, "./ssl.pem" ++ [0]), + io:format("port_control: ~p~n", [PCRes]), + {ok, ListenSocket} = gen_tcp:listen(1234, [binary, + {packet, 0}, + {active, true}, + {reuseaddr, true}, + {nodelay, true}]), + io:format("listen: ~p~n", [ListenSocket]), + {ok, Socket} = gen_tcp:accept(ListenSocket), + io:format("accept: ~p~n", [Socket]), + loop(Port, Socket). + + +loop(Port, Socket) -> + receive + {tcp, Socket, Data} -> + %io:format("read: ~p~n", [Data]), + Res = port_control(Port, ?SET_ENCRYPTED_INPUT, Data), + %io:format("SET_ENCRYPTED_INPUT: ~p~n", [Res]), + + DIRes = port_control(Port, ?GET_DECRYPTED_INPUT, Data), + %io:format("GET_DECRYPTED_INPUT: ~p~n", [DIRes]), + case DIRes of + [0 | In] -> + io:format("input: ~s~n", [In]); + [1 | DIError] -> + io:format("GET_DECRYPTED_INPUT error: ~p~n", [DIError]) + end, + + EORes = port_control(Port, ?GET_ENCRYPTED_OUTPUT, Data), + %io:format("GET_ENCRYPTED_OUTPUT: ~p~n", [EORes]), + case EORes of + [0 | Out] -> + gen_tcp:send(Socket, Out); + [1 | EOError] -> + io:format("GET_ENCRYPTED_OUTPUT error: ~p~n", [EOError]) + end, + + + loop(Port, Socket); + Msg -> + io:format("receive: ~p~n", [Msg]), + loop(Port, Socket) + end. + + diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c new file mode 100644 index 000000000..23d42b464 --- /dev/null +++ b/src/tls/tls_drv.c @@ -0,0 +1,188 @@ +/* $Id$ */ + +#include +#include +#include +#include + + +#define BUF_SIZE 1024 + +typedef struct { + ErlDrvPort port; + SSL_CTX *ctx; + BIO *bio_read; + BIO *bio_write; + SSL *ssl; +} tls_data; + + +static ErlDrvData tls_drv_start(ErlDrvPort port, char *buff) +{ + tls_data *d = (tls_data *)driver_alloc(sizeof(tls_data)); + d->port = port; + d->ctx = NULL; + d->bio_read = NULL; + d->bio_write = NULL; + d->ssl = NULL; + + return (ErlDrvData)d; +} + +static void tls_drv_stop(ErlDrvData handle) +{ + // TODO + //XML_ParserFree(((tls_data *)handle)->parser); + driver_free((char *)handle); +} + + +#define SET_CERTIFICATE_FILE 1 +#define SET_ENCRYPTED_INPUT 2 +#define SET_DECRYPTED_OUTPUT 3 +#define GET_ENCRYPTED_OUTPUT 4 +#define GET_DECRYPTED_INPUT 5 + +#define DECRYPTED_INPUT 1 +#define ENCRYPTED_OUTPUT 2 + +#define die_unless(cond, errstr) \ + if (!(cond)) \ + { \ + rlen = strlen(errstr) + 1; \ + *rbuf = driver_alloc(rlen); \ + *rbuf[0] = 1; \ + strncpy(*rbuf + 1, errstr, rlen - 1); \ + return rlen; \ + } + + +static int tls_drv_control(ErlDrvData handle, + unsigned int command, + char *buf, int len, + char **rbuf, int rlen) +{ + tls_data *d = (tls_data *)handle; + int res; + int size; + + switch (command) + { + case SET_CERTIFICATE_FILE: + d->ctx = SSL_CTX_new(SSLv23_server_method()); + die_unless(d->ctx, "SSL_CTX_new failed"); + + res = SSL_CTX_use_certificate_file(d->ctx, buf, SSL_FILETYPE_PEM); + die_unless(res > 0, "SSL_CTX_use_certificate_file failed"); + + res = SSL_CTX_use_PrivateKey_file(d->ctx, buf, SSL_FILETYPE_PEM); + die_unless(res > 0, "SSL_CTX_use_PrivateKey_file failed"); + + res = SSL_CTX_check_private_key(d->ctx); + die_unless(res > 0, "SSL_CTX_check_private_key failed"); + + d->ssl = SSL_new(d->ctx); + die_unless(d->ssl, "SSL_new failed"); + + d->bio_read = BIO_new(BIO_s_mem()); + d->bio_write = BIO_new(BIO_s_mem()); + + SSL_set_bio(d->ssl, d->bio_read, d->bio_write); + + SSL_set_accept_state(d->ssl); + break; + case SET_ENCRYPTED_INPUT: + BIO_write(d->bio_read, buf, len); + break; + case SET_DECRYPTED_OUTPUT: + res = SSL_write(d->ssl, buf, len); + break; + case GET_ENCRYPTED_OUTPUT: + size = BUF_SIZE + 1; + rlen = 1; + *rbuf = driver_alloc(size); + *rbuf[0] = 0; + while ((res = BIO_read(d->bio_write, *rbuf + rlen, BUF_SIZE)) > 0) + { + printf("%d bytes of encrypted data read from state machine\r\n", res); + + rlen += res; + size += BUF_SIZE; + *rbuf = driver_realloc(*rbuf, size); + } + return rlen; + case GET_DECRYPTED_INPUT: + if (!SSL_is_init_finished(d->ssl)) + { + printf("Doing SSL_accept\r\n"); + res = SSL_accept(d->ssl); + if (res == 0) + printf("SSL_accept returned zero\r\n"); + if (res < 0) + die_unless(SSL_get_error(d->ssl, res) == SSL_ERROR_WANT_READ, + "SSL_accept failed"); + } else { + size = BUF_SIZE + 1; + rlen = 1; + *rbuf = driver_alloc(size); + *rbuf[0] = 0; + + + while ((res = SSL_read(d->ssl, *rbuf + rlen, BUF_SIZE)) > 0) + { + printf("%d bytes of decrypted data read from state machine\r\n",res); + rlen += res; + size += BUF_SIZE; + *rbuf = driver_realloc(*rbuf, size); + } + + if (res < 0) + { + int err = SSL_get_error(d->ssl, res); + + if (err == SSL_ERROR_WANT_READ) + { + printf("SSL_read wants more data\r\n"); + //return 0; + } + // TODO + } + return rlen; + } + break; + } + + if (command == SET_ENCRYPTED_INPUT || command == SET_DECRYPTED_OUTPUT) + { + + } + + *rbuf = driver_alloc(1); + *rbuf[0] = 0; + return 1; +} + + +ErlDrvEntry tls_driver_entry = { + NULL, /* F_PTR init, N/A */ + tls_drv_start, /* L_PTR start, called when port is opened */ + tls_drv_stop, /* F_PTR stop, called when port is closed */ + NULL, /* F_PTR output, called when erlang has sent */ + NULL, /* F_PTR ready_input, called when input descriptor ready */ + NULL, /* F_PTR ready_output, called when output descriptor ready */ + "tls_drv", /* char *driver_name, the argument to open_port */ + NULL, /* F_PTR finish, called when unloaded */ + NULL, /* handle */ + tls_drv_control, /* F_PTR control, port_command callback */ + NULL, /* F_PTR timeout, reserved */ + NULL /* F_PTR outputv, reserved */ +}; + +DRIVER_INIT(tls_drv) /* must match name in driver_entry */ +{ + OpenSSL_add_ssl_algorithms(); + SSL_load_error_strings(); + return &tls_driver_entry; +} + +