Wed, 13 Jan 2010 00:04:38 +0000
prosodyctl: Use mode r+ for opening the file so 1) it fails if the file doesn't exist 2) we have write access to lock it
1523
841d61be198f
Remove version number from copyright headers
Matthew Wild <mwild1@gmail.com>
parents:
894
diff
changeset
|
1 | -- Prosody IM |
875 | 2 | -- Copyright (C) 2008-2009 Matthew Wild |
3 | -- Copyright (C) 2008-2009 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 | module.host = "*" -- Global module | |
11 | ||
12 | local httpserver = require "net.httpserver"; | |
13 | local st = require "util.stanza"; | |
14 | local pcall = pcall; | |
15 | local unpack = unpack; | |
16 | local tostring = tostring; | |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
17 | local is_admin = require "core.usermanager".is_admin; |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
18 | local jid_split = require "util.jid".split; |
1587
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
19 | local jid_bare = require "util.jid".bare; |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
20 | local b64_decode = require "util.encodings".base64.decode; |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
21 | local get_method = require "core.objectmanager".get_object; |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
22 | local validate_credentials = require "core.usermanager".validate_credentials; |
875 | 23 | |
24 | local translate_request = require "util.xmlrpc".translate_request; | |
25 | local create_response = require "util.xmlrpc".create_response; | |
26 | local create_error_response = require "util.xmlrpc".create_error_response; | |
27 | ||
28 | local entity_map = setmetatable({ | |
29 | ["amp"] = "&"; | |
30 | ["gt"] = ">"; | |
31 | ["lt"] = "<"; | |
32 | ["apos"] = "'"; | |
33 | ["quot"] = "\""; | |
34 | }, {__index = function(_, s) | |
35 | if s:sub(1,1) == "#" then | |
36 | if s:sub(2,2) == "x" then | |
37 | return string.char(tonumber(s:sub(3), 16)); | |
38 | else | |
39 | return string.char(tonumber(s:sub(2))); | |
40 | end | |
41 | end | |
42 | end | |
43 | }); | |
44 | local function xml_unescape(str) | |
45 | return (str:gsub("&(.-);", entity_map)); | |
46 | end | |
47 | local function parse_xml(xml) | |
48 | local stanza = st.stanza("root"); | |
49 | local regexp = "<([^>]*)>([^<]*)"; | |
50 | for elem, text in xml:gmatch(regexp) do | |
51 | --print("[<"..elem..">|"..text.."]"); | |
52 | if elem:sub(1,1) == "!" or elem:sub(1,1) == "?" then -- neglect comments and processing-instructions | |
53 | elseif elem:sub(1,1) == "/" then -- end tag | |
54 | elem = elem:sub(2); | |
55 | stanza:up(); -- TODO check for start-end tag name match | |
56 | elseif elem:sub(-1,-1) == "/" then -- empty tag | |
57 | elem = elem:sub(1,-2); | |
58 | stanza:tag(elem):up(); | |
59 | else -- start tag | |
60 | stanza:tag(elem); | |
61 | end | |
62 | if #text ~= 0 then -- text | |
63 | stanza:text(xml_unescape(text)); | |
64 | end | |
65 | end | |
66 | return stanza.tags[1]; | |
67 | end | |
68 | ||
1587
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
69 | local function handle_xmlrpc_request(jid, method, args) |
1590 | 70 | local is_secure_call = (method:sub(1,7) == "secure/"); |
1587
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
71 | if not is_admin(jid) and not is_secure_call then |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
72 | return create_error_response(401, "not authorized"); |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
73 | end |
875 | 74 | method = get_method(method); |
75 | if not method then return create_error_response(404, "method not found"); end | |
76 | args = args or {}; | |
1590 | 77 | if is_secure_call then table.insert(args, 1, jid); end |
875 | 78 | local success, result = pcall(method, unpack(args)); |
79 | if success then | |
80 | success, result = pcall(create_response, result or "nil"); | |
81 | if success then | |
82 | return result; | |
83 | end | |
84 | return create_error_response(500, "Error in creating response: "..result); | |
85 | end | |
1640
726ac98306d8
mod_xmlrpc: Correct stripping of filename/line number prefix in RPC method error results
Matthew Wild <mwild1@gmail.com>
parents:
1591
diff
changeset
|
86 | return create_error_response(0, tostring(result):gsub("^[^:]+:%d+: ", "")); |
875 | 87 | end |
88 | ||
877
0bababc930dd
mod_xmlrpc: Handle RPC stanzas sent over XMPP (XEP-0009: Jabber-RPC)
Waqas Hussain <waqas20@gmail.com>
parents:
875
diff
changeset
|
89 | local function handle_xmpp_request(origin, stanza) |
875 | 90 | local query = stanza.tags[1]; |
91 | if query.name == "query" then | |
92 | if #query.tags == 1 then | |
1587
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
93 | local success, method, args = pcall(translate_request, query.tags[1]); |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
94 | if success then |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
95 | local result = handle_xmlrpc_request(jid_bare(stanza.attr.from), method, args); |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
96 | origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:rpc'}):add_child(result)); |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
97 | else |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
98 | origin.send(st.error_reply(stanza, "modify", "bad-request", method)); |
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
99 | end |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
100 | else origin.send(st.error_reply(stanza, "modify", "bad-request", "No content in XML-RPC request")); end |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
101 | else origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end |
875 | 102 | end |
877
0bababc930dd
mod_xmlrpc: Handle RPC stanzas sent over XMPP (XEP-0009: Jabber-RPC)
Waqas Hussain <waqas20@gmail.com>
parents:
875
diff
changeset
|
103 | module:add_iq_handler({"c2s", "s2sin"}, "jabber:iq:rpc", handle_xmpp_request); |
0bababc930dd
mod_xmlrpc: Handle RPC stanzas sent over XMPP (XEP-0009: Jabber-RPC)
Waqas Hussain <waqas20@gmail.com>
parents:
875
diff
changeset
|
104 | module:add_feature("jabber:iq:rpc"); |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
105 | -- TODO add <identity category='automation' type='rpc'/> to disco replies |
875 | 106 | |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
107 | local default_headers = { ['Content-Type'] = 'text/xml' }; |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
108 | local unauthorized_response = { status = '401 UNAUTHORIZED', headers = {['Content-Type']='text/html', ['WWW-Authenticate']='Basic realm="WallyWorld"'}; body = "<html><body>Authentication required</body></html>"; }; |
875 | 109 | local function handle_http_request(method, body, request) |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
110 | -- authenticate user |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
111 | local username, password = b64_decode(request['authorization'] or ''):gmatch('([^:]*):(.*)')(); -- TODO digest auth |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
112 | local node, host = jid_split(username); |
1587
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
113 | if not validate_credentials(host, node, password) then |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
114 | return unauthorized_response; |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
115 | end |
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
116 | -- parse request |
875 | 117 | local stanza = body and parse_xml(body); |
118 | if (not stanza) or request.method ~= "POST" then | |
119 | return "<html><body>You really don't look like an XML-RPC client to me... what do you want?</body></html>"; | |
120 | end | |
892
2128891180b7
mod_xmlrpc: Limit usage to admins
Waqas Hussain <waqas20@gmail.com>
parents:
889
diff
changeset
|
121 | -- execute request |
875 | 122 | local success, method, args = pcall(translate_request, stanza); |
123 | if success then | |
1587
81992255a374
mod_xmlrpc: Added support for secure calls by non-admins
Waqas Hussain <waqas20@gmail.com>
parents:
1523
diff
changeset
|
124 | return { headers = default_headers; body = tostring(handle_xmlrpc_request(node.."@"..host, method, args)) }; |
875 | 125 | end |
880
ff4a08d73772
XML-RPC: Set appropriate Content-Type header in HTTP response
Waqas Hussain <waqas20@gmail.com>
parents:
877
diff
changeset
|
126 | return "<html><body>Error parsing XML-RPC request: "..tostring(method).."</body></html>"; |
875 | 127 | end |
128 | httpserver.new{ port = 9000, base = "xmlrpc", handler = handle_http_request } |