diff --git a/apps/kolab_guam/src/rules/kolab_guam_rule_audit.erl b/apps/kolab_guam/src/rules/kolab_guam_rule_audit.erl index 36ec8a5..86618f0 100644 --- a/apps/kolab_guam/src/rules/kolab_guam_rule_audit.erl +++ b/apps/kolab_guam/src/rules/kolab_guam_rule_audit.erl @@ -1,93 +1,92 @@ %% Copyright 2021 Apheleia IT AG (http://www.apheleia.ch) %% %% Aaron Seigo (Kolab Systems) %% Christian Mollekopf (Apheleia IT) %% %% This program is free software: you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation, either version 3 of the License, or %% (at your option) any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program. If not, see . -module(kolab_guam_rule_audit). -export([new/1, applies/4, imap_data/3, apply_to_client_message/4, apply_to_server_message/3]). -behavior(kolab_guam_rule). -include("kolab_guam_rule_audit.hrl"). new(_Config) -> #state { }. applies(Socket, _Buffer, { _Tag, _Command, _Data }, State) -> {ok, {Ip, _Port}} = inet:peername(Socket), % This command is always immediately active as we expect the LOGIN command at the beginning { true, State#state{ ip = Ip }}. % Unused imap_data(_ResponseToken, _Response, State) -> State. apply_to_client_message(_ImapSession, Buffer, undefined, State) -> { Buffer, State }; % We just buffer the entire command once activated apply_to_client_message(_ImapSession, Buffer, { _Tag, _Command, _Data }, #state{ buffer = LeftOvers, active = true } = State) -> { Buffer, State#state{ buffer = <> }}; % Monitor for the trigger command, otherwise do nothing apply_to_client_message(ImapSession, Buffer, { Tag, Command, Data }, State) -> case is_triggering_command(Command, Data, State) of true -> apply_to_client_message(ImapSession, Buffer, { Tag, Command, Data }, State#state{ active = true, tag = Tag, command = Command }); _ -> { Buffer, State } end. apply_to_server_message(_ImapSession, Buffer, #state{ active = true, tag = Tag, ip = Ip, buffer = FullBuffer, command = Command } = State) -> NewState = case eimap_utils:is_tagged_response(Buffer, Tag) of tagged -> Username = extract_username(FullBuffer, Command), case eimap_utils:check_response_for_failure(Buffer, Tag) of ok -> - lager:info("LOGIN ATTEMPT: ~p from ~p, OK", [Username, inet:ntoa(Ip)]), + lager:info("login: ~s from ~s, OK", [Username, inet:ntoa(Ip)]), State#state{ active = false, username = Username }; { no, Reason } -> - lager:info("LOGIN ATTEMPT: ~p from ~p, NO: ~p", [Username, inet:ntoa(Ip), Reason]), + lager:info("badlogin: ~s from ~s, NO: ~s", [Username, inet:ntoa(Ip), Reason]), State#state{ active = false, username = Username }; { bad, Reason } -> - lager:info("LOGIN ATTEMPT: ~p from ~p, BAD: ~p", [Username, inet:ntoa(Ip), Reason]), + lager:info("badlogin: ~s from ~s, BAD: ~s", [Username, inet:ntoa(Ip), Reason]), State#state{ active = false, username = Username } end; untagged -> State end, { Buffer, NewState }; % Do nothing if not active apply_to_server_message(_ImapSession, Buffer, State) -> { Buffer, State }. %%PRIVATE is_triggering_command(Command, Data, #state{ trigger_commands = TriggerCommands }) -> %% if the command is in the list of trigger commands and the ending is not "" (which means "send me %% the root and separator" according to RFC 3501), then it is treated as a triggering event lists:any(fun(T) -> (Command =:= T) andalso (binary:longest_common_suffix([Data, <<"\"\"">>]) =/= 2) end, TriggerCommands). extract_username(FullBuffer, Command) -> case Command of Command when Command =:= <<"AUTHENTICATE">>; Command =:= <<"authenticate">> -> Lines = binary:split(FullBuffer, <<"\r\n">>, [ global ]), % We can only handle the LOGIN method - lager:info("Lines ~p", [Lines]), base64:decode(lists:nth(2, Lines)); <<"LOGIN">> -> List = binary:split(FullBuffer, <<" ">>, [ global ]), lists:nth(3, List) end.