]> granicus.if.org Git - ejabberd/commitdiff
*** empty log message ***
authorAlexey Shchepin <alexey@process-one.net>
Tue, 21 Jan 2003 20:36:55 +0000 (20:36 +0000)
committerAlexey Shchepin <alexey@process-one.net>
Tue, 21 Jan 2003 20:36:55 +0000 (20:36 +0000)
SVN Revision: 46

13 files changed:
TODO
src/acl.erl
src/ejabberd.cfg
src/ejabberd.erl
src/ejabberd.hrl
src/ejabberd_auth.erl
src/ejabberd_config.erl
src/ejabberd_listener.erl
src/ejabberd_router.erl
src/ejabberd_s2s.erl
src/ejabberd_sm.erl
src/mod_configure.erl
src/mod_disco.erl

diff --git a/TODO b/TODO
index 248c97fb16e625832b6c9c128c3edaf2ff280aca..af37fc29675fc9171af448c23fa3dc8a33f134f2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,6 +3,7 @@ admin interface
        node management
        backup management
 S2S timeouts
+rewrite S2S key validation
 iq:browse(?)
 SVR DNS records
 karma
index b9c2314753fa1a524c21f14b2eabae99e695c777..375f694908cff30a1848ebb20f82c7f4ca532f87 100644 (file)
 -include("ejabberd.hrl").
 
 start() ->
-    ets:new(acls, [bag, named_table, public]).
+    ets:new(acls, [bag, named_table, public]),
+    ok.
 
 
 add(ACLName, ACLData) ->
     ets:insert(acls, {ACLName, ACLData}).
 
 match_rule(Rule, JID) ->
-    case ejabberd_config:get_option(Rule) of
+    case ejabberd_config:get_global_option({access, Rule}) of
        undefined ->
            deny;
        ACLs ->
index 6d3d6521ddca6d9322c11c74f7bb9e37783fdd06..464a1f7a1af43b5a35ce52814db7e1e4979bbf30 100644 (file)
@@ -9,10 +9,10 @@
 {acl, jabberorg, {server, "jabber.org"}}.
 {acl, aleksey, {user, "aleksey", "jabber.ru"}}.
 
-{disco_admin, [{allow, admin},
-              {deny, all}]}.
+{access, disco_admin, [{allow, admin},
+                      {deny, all}]}.
 
-{configure, [{allow, admin}]}.
+{access, configure, [{allow, admin}]}.
 
 {host, "e.localhost"}.
 
index e02773594276127d63cf59aadbec637101695318..0e4f509546b1ded722da64a0c2fccf5940e3c194 100644 (file)
@@ -45,6 +45,11 @@ loop(Port) ->
     end.
 
 db_init() ->
-    mnesia:create_schema([node()]),
+    case mnesia:system_info(extra_db_nodes) of
+       [] ->
+           mnesia:create_schema([node()]);
+       _ ->
+           ok
+    end,
     mnesia:start(),
-    mnesia:wait_for_tables(mnesia:system_info(tables), infinity).
+    mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity).
index 44adc0db4b4633d496c193d6237fe27ef9100cf7..5e453fd5b55b1ced6aa90784691bd49c56624119 100644 (file)
@@ -24,7 +24,7 @@
 
 
 %-define(MYNAME,"e.localhost").
--define(MYNAME, ejabberd_config:get_option(host)).
+-define(MYNAME, ejabberd_config:get_global_option(host)).
 
 -define(MSGS_DIR, "msgs").
 -define(CONFIG_PATH, "ejabberd.cfg").
index 7e0aa428409a6e69839bc3eb2ab3a1a0cbb1a3e8..809d3dfd862374f7dbd938f04961b2ce28864fd5 100644 (file)
@@ -22,6 +22,7 @@
         check_password/4,
         try_register/2,
         dirty_get_registered_users/0,
+        get_password_s/1,
         is_user_exists/1]).
 
 %% gen_server callbacks
@@ -163,6 +164,15 @@ try_register(User, Password) ->
 dirty_get_registered_users() ->
     mnesia:dirty_all_keys(passwd).
 
+get_password_s(User) ->
+    LUser = jlib:tolower(User),
+    case catch mnesia:dirty_read(passwd, LUser) of
+       [#passwd{password = Password}] ->
+           Password;
+       _ ->
+           []
+    end.
+
 is_user_exists(User) ->
     LUser = jlib:tolower(User),
     F = fun() ->
index 1bae8a9fddab8d3e4b645d24d16278a876dfa81b..40dc97bf2993426c2c4a7aedb73a35571afe833b 100644 (file)
 -author('alexey@sevcom.net').
 -vsn('$Revision$ ').
 
--export([start/0, load_file/1, get_option/1]).
+-export([start/0, load_file/1,
+        add_global_option/2, add_local_option/2,
+        get_global_option/1, get_local_option/1]).
 
 -include("ejabberd.hrl").
 
+-record(config, {key, value}).
+-record(local_config, {key, value}).
+
 start() ->
-    ets:new(ejabberd_config, [named_table, public]),
+    %ets:new(ejabberd_config, [named_table, public]),
+    mnesia:create_table(config,
+                       [{disc_copies, [node()]},
+                        {attributes, record_info(fields, config)}]),
+    mnesia:add_table_copy(config, node(), ram_copies),
+    mnesia:create_table(local_config,
+                       [{disc_copies, [node()]},
+                        {local_content, true},
+                        {attributes, record_info(fields, local_config)}]),
+    mnesia:add_table_copy(local_config, node(), ram_copies),
     load_file(?CONFIG_PATH).
 
 
@@ -31,14 +45,50 @@ process_term(Term) ->
     case Term of
        {acl, ACLName, ACLData} ->
            acl:add(ACLName, ACLData);
+       {access, RuleName, Rules} ->
+           add_global_option({access, RuleName}, Rules);
        {Opt, Val} ->
-           ets:insert(ejabberd_config, {Opt, Val})
+           add_option(Opt, Val)
+    end.
+
+add_option(Opt, Val) ->
+    Table = case Opt of
+               host ->
+                   config;
+               _ ->
+                   local_config
+           end,
+    case Table of
+       config ->
+           add_global_option(Opt, Val);
+       local_config ->
+           add_local_option(Opt, Val)
     end.
 
+add_global_option(Opt, Val) ->
+    mnesia:transaction(fun() ->
+                              mnesia:write(#config{key = Opt,
+                                                   value = Val})
+                      end).
+
+add_local_option(Opt, Val) ->
+    mnesia:transaction(fun() ->
+                              mnesia:write(#local_config{key = Opt,
+                                                         value = Val})
+                      end).
+
+
+get_global_option(Opt) ->
+    case ets:lookup(config, Opt) of
+       [#config{value = Val}] ->
+           Val;
+       _ ->
+           undefined
+    end.
 
-get_option(Opt) ->
-    case ets:lookup(ejabberd_config, Opt) of
-       [{_, Val}] ->
+get_local_option(Opt) ->
+    case ets:lookup(local_config, Opt) of
+       [#local_config{value = Val}] ->
            Val;
        _ ->
            undefined
index c09733515df8d7aa67fa720e5c13ef7cd145b058..9e6957c476548d76bfa35017fd78d1c594df02ad 100644 (file)
@@ -17,7 +17,7 @@ start() ->
 
 
 init(_) ->
-    case ejabberd_config:get_option(listen) of
+    case ejabberd_config:get_local_option(listen) of
        undefined ->
            ignore;
        Ls ->
index 0ef1a93e2a845ad2e58fc8383f8e04494ee7069d..97599026320bf49d8d384845012e732bccf36303 100644 (file)
@@ -41,6 +41,7 @@ init() ->
                         {local_content, true},
                         {attributes,
                          record_info(fields, local_route)}]),
+    mnesia:add_table_copy(local_route, node(), ram_copies),
     loop().
 
 loop() ->
index d834dea5c62af8779f7a133be70ef6e0f5513cf9..3a2d19a58d8e8f1c4af043c9868056b4e4b6b136 100644 (file)
@@ -20,7 +20,7 @@
 -include("ejabberd.hrl").
 
 -record(s2s, {fromto, node, key}).
--record(mys2s, {fromto, pid}).
+-record(local_s2s, {fromto, pid}).
 
 
 start() ->
@@ -31,10 +31,11 @@ init() ->
     mnesia:create_table(s2s,[{ram_copies, [node()]},
                             {attributes, record_info(fields, s2s)}]),
     mnesia:add_table_index(session, node),
-    mnesia:create_table(mys2s,
+    mnesia:create_table(local_s2s,
                        [{ram_copies, [node()]},
                         {local_content, true},
-                        {attributes, record_info(fields, mys2s)}]),
+                        {attributes, record_info(fields, local_s2s)}]),
+    mnesia:add_table_copy(local_s2s, node(), ram_copies),
     mnesia:subscribe(system),
     loop().
 
@@ -70,7 +71,7 @@ loop() ->
 
 remove_connection(FromTo) ->
     F = fun() ->
-               mnesia:delete({mys2s, FromTo}),
+               mnesia:delete({local_s2s, FromTo}),
                mnesia:delete({s2s, FromTo})
        end,
     mnesia:transaction(F).
@@ -133,8 +134,8 @@ try_register(FromTo) ->
                        mnesia:write(#s2s{fromto = FromTo,
                                          node = node(),
                                          key = Key}),
-                       mnesia:write(#mys2s{fromto = FromTo,
-                                           pid = self()}),
+                       mnesia:write(#local_s2s{fromto = FromTo,
+                                               pid = self()}),
                        {key, Key};
                    _ ->
                        false
@@ -159,7 +160,7 @@ do_route(From, To, Packet) ->
     FromTo = {MyServer, Server},
     Key = randoms:get_string(),
     F = fun() ->
-               case mnesia:read({mys2s, FromTo}) of
+               case mnesia:read({local_s2s, FromTo}) of
                    [] ->
                        case mnesia:read({s2s, FromTo}) of
                            [Er] ->
@@ -172,7 +173,7 @@ do_route(From, To, Packet) ->
                                new
                        end;
                    [El] ->
-                       {local, El#mys2s.pid}
+                       {local, El#local_s2s.pid}
                end
         end,
     case mnesia:transaction(F) of
@@ -192,8 +193,10 @@ do_route(From, To, Packet) ->
        {atomic, new} ->
            ?DEBUG("starting new s2s connection~n", []),
            Pid = ejabberd_s2s_out:start(MyServer, Server, {new, Key}),
-           mnesia:transaction(fun() -> mnesia:write(#mys2s{fromto = FromTo,
-                                                           pid = Pid}) end),
+           mnesia:transaction(fun() ->
+                                      mnesia:write(#local_s2s{fromto = FromTo,
+                                                              pid = Pid})
+                              end),
            {xmlelement, Name, Attrs, Els} = Packet,
            NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From),
                                                  jlib:jid_to_string(To),
index cbb695beae1012a0053f6c82dc4ed8043a29a9f7..9e74177eaf2054a91fa01f4885e21ca2cec04d50 100644 (file)
@@ -22,7 +22,7 @@
 -include("ejabberd.hrl").
 
 -record(session, {ur, user, node}).
--record(mysession, {ur, pid}).
+-record(local_session, {ur, pid}).
 -record(presence, {ur, user, priority}).
 
 start() ->
@@ -34,10 +34,11 @@ init() ->
                                  {attributes, record_info(fields, session)}]),
     mnesia:add_table_index(session, user),
     mnesia:add_table_index(session, node),
-    mnesia:create_table(mysession,
+    mnesia:create_table(local_session,
                        [{ram_copies, [node()]},
                         {local_content, true},
-                        {attributes, record_info(fields, mysession)}]),
+                        {attributes, record_info(fields, local_session)}]),
+    mnesia:add_table_copy(local_session, node(), ram_copies),
     mnesia:create_table(presence,
                        [{ram_copies, [node()]},
                         {attributes, record_info(fields, presence)}]),
@@ -111,15 +112,15 @@ replace_my_connection(User, Resource) ->
     LUser = jlib:tolower(User),
     F = fun() ->
                UR = {LUser, Resource},
-               Es = mnesia:read({mysession, UR}),
-               mnesia:delete({mysession, UR}),
+               Es = mnesia:read({local_session, UR}),
+               mnesia:delete({local_session, UR}),
                Es
         end,
     case mnesia:transaction(F) of
        {atomic, Rs} ->
            lists:foreach(
              fun(R) ->
-                     R#mysession.pid ! replaced
+                     R#local_session.pid ! replaced
              end, Rs);
        _ ->
            false
@@ -129,7 +130,7 @@ remove_connection(User, Resource) ->
     LUser = jlib:tolower(User),
     F = fun() ->
                UR = {LUser, Resource},
-               mnesia:delete({mysession, UR}),
+               mnesia:delete({local_session, UR}),
                mnesia:delete({session, UR})
         end,
     mnesia:transaction(F).
@@ -138,15 +139,15 @@ replace_and_register_my_connection(User, Resource, Pid) ->
     LUser = jlib:tolower(User),
     F = fun() ->
                UR = {LUser, Resource},
-               Es = mnesia:read({mysession, UR}),
-               mnesia:write(#mysession{ur = UR, pid = Pid}),
+               Es = mnesia:read({local_session, UR}),
+               mnesia:write(#local_session{ur = UR, pid = Pid}),
                Es
         end,
     case mnesia:transaction(F) of
        {atomic, Rs} ->
            lists:foreach(
              fun(R) ->
-                     R#mysession.pid ! replaced
+                     R#local_session.pid ! replaced
              end, Rs);
        _ ->
            false
@@ -262,13 +263,13 @@ do_route(From, To, Packet) ->
                            ?DEBUG("packet droped~n", [])
                    end;
                [Ses] ->
-                   case mnesia:dirty_read({mysession, LUR}) of
+                   case mnesia:dirty_read({local_session, LUR}) of
                        [] ->
                            Node = Ses#session.node,
                            ?DEBUG("sending to node ~p~n", [Node]),
                            {ejabberd_sm, Node} ! {route, From, To, Packet};
                        [El] ->
-                           Pid = El#mysession.pid,
+                           Pid = El#local_session.pid,
                            ?DEBUG("sending to process ~p~n", [Pid]),
                            Pid ! {route, From, To, Packet}
                    end
@@ -341,7 +342,7 @@ dirty_get_sessions_list() ->
     mnesia:dirty_all_keys(session).
 
 dirty_get_my_sessions_list() ->
-    mnesia:dirty_all_keys(mysession).
+    mnesia:dirty_all_keys(local_session).
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
index b72f180b58860d7fdf90880817785e2c2a53087b..5ae67513fd1dbf5e7cd99d8bbdf95a018b24a08c 100644 (file)
@@ -11,7 +11,8 @@
 -vsn('$Revision$ ').
 
 -export([start/0,
-        process_local_iq/3]).
+        process_local_iq/3,
+        process_sm_iq/3]).
 
 -include("ejabberd.hrl").
 -include("namespaces.hrl").
 
 start() ->
     ejabberd_local:register_iq_handler(?NS_XDATA,
-                                      ?MODULE, process_local_iq).
+                                      ?MODULE, process_local_iq),
+    ejabberd_sm:register_iq_handler(?NS_XDATA,
+                                   ?MODULE, process_sm_iq),
+    ok.
 
 
 process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
@@ -92,6 +96,12 @@ process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
                               {"label", translate:translate(Lang, Label)},
                               {"var", Var}], []}).
 
+-define(XFIELD(Type, Label, Var, Val),
+       {xmlelement, "field", [{"type", Type},
+                              {"label", translate:translate(Lang, Label)},
+                              {"var", Var}],
+        [{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
+
 -define(TABLEFIELD(Table, Val),
        {xmlelement, "field", [{"type", "list-single"},
                               {"label", atom_to_list(Table)},
@@ -105,7 +115,8 @@ process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
                                                       "RAM and disc copy")}],
           [{xmlelement, "value", [], [{xmlcdata, "disc_copies"}]}]},
          {xmlelement, "option", [{"label",
-                                  translate:translate(Lang, "Disk copy")}],
+                                  translate:translate(Lang,
+                                                      "Disc only copy")}],
           [{xmlelement, "value", [], [{xmlcdata, "disc_only_copies"}]}]},
          {xmlelement, "option", [{"label",
                                   translate:translate(Lang, "Remote copy")}],
@@ -123,6 +134,7 @@ get_form(["running nodes", ENode, "DB"], Lang) ->
                {badrpc, Reason} ->
                    {error, "500", "Internal Server Error"};
                Tables ->
+                   STables = lists:sort(Tables),
                    {result, [{xmlelement, "title", [],
                               [{xmlcdata,
                                 translate:translate(
@@ -142,11 +154,27 @@ get_form(["running nodes", ENode, "DB"], Lang) ->
                                            Type ->
                                                ?TABLEFIELD(Table, Type)
                                        end
-                               end, Tables)
+                               end, STables)
                             ]}
            end
     end;
 
+get_form(["config", "hostname"], Lang) ->
+    {result, [{xmlelement, "title", [],
+              [{xmlcdata,
+                translate:translate(
+                  Lang, "DB Tables Configuration")}]},
+             {xmlelement, "instructions", [],
+              [{xmlcdata,
+                translate:translate(
+                  Lang, "Choose host name")}]},
+             {xmlelement, "field", [{"type", "text-single"},
+                                    {"label",
+                                     translate:translate(Lang, "Host name")},
+                                    {"var", "hostname"}],
+              [{xmlelement, "value", [], [{xmlcdata, ?MYNAME}]}]}
+            ]};
+
 get_form(_, Lang) ->
     {error, "503", "Service Unavailable"}.
 
@@ -159,7 +187,7 @@ set_form(["running nodes", ENode, "DB"], Lang, XData) ->
        Node ->
            lists:foreach(
              fun({SVar, SVals}) ->
-                     % We believe that this allowed only for good peoples
+                     % We believe that this is allowed only for good peoples
                      Table = list_to_atom(SVar),
                      Type = case SVals of
                                 ["unknown"] -> unknown;
@@ -186,6 +214,19 @@ set_form(["running nodes", ENode, "DB"], Lang, XData) ->
            {result, []}
     end;
 
+set_form(["config", "hostname"], Lang, XData) ->
+    case lists:keysearch("hostname", 1, XData) of
+       false ->
+           {error, "406", "Not Acceptable"};
+       {value, {_, [""]}} ->
+           {error, "406", "Not Acceptable"};
+       {value, {_, [NewName]}} ->
+           ejabberd_config:add_global_option(hostname, NewName),
+           {result, []};
+       _ ->
+           {error, "406", "Not Acceptable"}
+    end;
+
 set_form(_, Lang, XData) ->
     {error, "503", "Service Unavailable"}.
 
@@ -204,4 +245,97 @@ search_running_node(SNode, [Node | Nodes]) ->
            search_running_node(SNode, Nodes)
     end.
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+process_sm_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
+    case acl:match_rule(configure, From) of
+       deny ->
+           {iq, ID, error, XMLNS, [SubEl, {xmlelement, "error",
+                                           [{"code", "405"}],
+                                           [{xmlcdata, "Not Allowed"}]}]};
+       allow ->
+           {User, _, _} = To,
+           Lang = xml:get_tag_attr_s("xml:lang", SubEl),
+           case Type of
+               set ->
+                   case xml:get_tag_attr_s("type", SubEl) of
+                       "cancel" ->
+                           {iq, ID, result, XMLNS,
+                            [{xmlelement, "query", [{"xmlns", XMLNS}], []}]};
+                       "submit" ->
+                           XData = jlib:parse_xdata_submit(SubEl),
+                           case XData of
+                               invalid ->
+                                   {iq, ID, error, XMLNS,
+                                    [SubEl, {xmlelement, "error",
+                                             [{"code", "400"}],
+                                             [{xmlcdata, "Bad Request"}]}]};
+                               _ ->
+                                   Node =
+                                       string:tokens(
+                                         xml:get_tag_attr_s("node", SubEl),
+                                         "/"),
+                                   case set_sm_form(
+                                          User, Node, Lang, XData) of
+                                       {result, Res} ->
+                                           {iq, ID, result, XMLNS,
+                                            [{xmlelement, "query",
+                                              [{"xmlns", XMLNS}],
+                                              Res
+                                             }]};
+                                       {error, Code, Desc} ->
+                                           {iq, ID, error, XMLNS,
+                                            [SubEl, {xmlelement, "error",
+                                                     [{"code", Code}],
+                                                     [{xmlcdata, Desc}]}]}
+                                   end
+                           end;
+                       _ ->
+                           {iq, ID, error, XMLNS,
+                            [SubEl, {xmlelement, "error",
+                                     [{"code", "405"}],
+                                     [{xmlcdata, "Not Allowed"}]}]}
+                   end;
+               get ->
+                   Node =
+                       string:tokens(xml:get_tag_attr_s("node", SubEl), "/"),
+                   case get_sm_form(User, Node, Lang) of
+                       {result, Res} ->
+                           {iq, ID, result, XMLNS,
+                            [{xmlelement, "query", [{"xmlns", XMLNS}],
+                              Res
+                             }]};
+                       {error, Code, Desc} ->
+                           {iq, ID, error, XMLNS,
+                            [SubEl, {xmlelement, "error",
+                                     [{"code", Code}],
+                                     [{xmlcdata, Desc}]}]}
+                   end
+           end
+    end.
+
+
+get_sm_form(User, [], Lang) ->
+    {result, [{xmlelement, "title", [],
+              [{xmlcdata,
+                translate:translate(
+                  Lang, "Administration of " ++ User)}]},
+             %{xmlelement, "instructions", [],
+             % [{xmlcdata,
+             %   translate:translate(
+             %     Lang, "Choose host name")}]},
+             ?XFIELD("text-private", "Password", "password",
+                     ejabberd_auth:get_password_s(User))
+             %{xmlelement, "field", [{"type", "text-single"},
+             %                      {"label",
+             %                       translate:translate(Lang, "Host name")},
+             %                      {"var", "hostname"}],
+             % [{xmlelement, "value", [], [{xmlcdata, ?MYNAME}]}]}
+            ]};
+
+get_sm_form(_, _, Lang) ->
+    {error, "503", "Service Unavailable"}.
+
+
+set_sm_form(_, _, Lang, XData) ->
+    {error, "503", "Service Unavailable"}.
index 9bf9c6dcfeaad72841f4cabde0fab8f0050bb857..b0574d31a4c3118000ee58f26a1e3b01f221c3a2 100644 (file)
@@ -90,6 +90,7 @@ process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
                                                 {"name", "ejabberd"}], []}] ++
                                              Features
                                             }]};
+               ["config"] -> ?EMPTY_INFO_RESULT;
                ["online users"] -> ?EMPTY_INFO_RESULT;
                ["all users"] -> ?EMPTY_INFO_RESULT;
                ["outgoing s2s" | _] -> ?EMPTY_INFO_RESULT;
@@ -98,7 +99,7 @@ process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
                ["running nodes", ENode] ->
                    {iq, ID, result, XMLNS, [{xmlelement,
                                              "query",
-                                             [{"xmlns", ?NS_DISCO_INFO}],
+                                             [{"xmlns", XMLNS}],
                                              [{xmlelement, "identity",
                                                [{"category", "ejabberd"},
                                                 {"type", "node"},
@@ -109,10 +110,14 @@ process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
                ["running nodes", ENode, "DB"] ->
                    {iq, ID, result, XMLNS, [{xmlelement,
                                              "query",
-                                             [{"xmlns", ?NS_DISCO_INFO}],
+                                             [{"xmlns", XMLNS}],
                                              [feature_to_xml({?NS_XDATA})
                                              ]
                                             }]};
+               ["config", _] ->
+                   {iq, ID, result, XMLNS,
+                    [{xmlelement, "query", [{"xmlns", XMLNS}],
+                      [feature_to_xml({?NS_XDATA})]}]};
                _ ->
                    {iq, ID, error, XMLNS,
                     [SubEl, {xmlelement, "error",
@@ -141,13 +146,24 @@ get_local_items([], Server, Lang) ->
        lists:map(fun domain_to_xml/1,
                  ejabberd_router:dirty_get_all_routes()),
     {result,
-       Domains ++
-       [?NODE("Online Users",             "online users"),
-       ?NODE("All Users",                "all users"),
-       ?NODE("Outgoing S2S connections", "outgoing s2s"),
-       ?NODE("Running Nodes",            "running nodes"),
-       ?NODE("Stopped Nodes",            "stopped nodes")
-       ]};
+     Domains ++
+     [?NODE("Configuration",            "config"),
+      ?NODE("Online Users",             "online users"),
+      ?NODE("All Users",                "all users"),
+      ?NODE("Outgoing S2S connections", "outgoing s2s"),
+      ?NODE("Running Nodes",            "running nodes"),
+      ?NODE("Stopped Nodes",            "stopped nodes")
+     ]};
+
+get_local_items(["config"], Server, Lang) ->
+    {result,
+     [?NODE("Host Name",    "config/hostname"),
+      ?NODE("ACLs",         "config/acls"),
+      ?NODE("Access Rules", "config/access")
+     ]};
+
+get_local_items(["config", _], Server, Lang) ->
+    {result, []};
 
 get_local_items(["online users"], Server, Lang) ->
     {result, get_online_users()};
@@ -310,7 +326,10 @@ process_sm_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
                                            [{xmlcdata, "Not Allowed"}]}]};
        get ->
            case xml:get_tag_attr_s("node", SubEl) of
-               "" -> ?EMPTY_INFO_RESULT;
+               "" ->
+                   {iq, ID, result, XMLNS,
+                    [{xmlelement, "query", [{"xmlns", XMLNS}],
+                      [feature_to_xml({?NS_XDATA})]}]};
                _ ->
                    {iq, ID, error, XMLNS,
                     [SubEl, {xmlelement, "error",