rpc.lua 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. -- Copyright 2008 Steven Barth <steven@midlink.org>
  2. -- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
  3. -- Licensed to the public under the Apache License 2.0.
  4. module("luci.controller.rpc", package.seeall)
  5. function session_retrieve(sid, allowed_users)
  6. local util = require "luci.util"
  7. local sdat = util.ubus("session", "get", {
  8. ubus_rpc_session = sid
  9. })
  10. if type(sdat) == "table" and
  11. type(sdat.values) == "table" and
  12. type(sdat.values.token) == "string" and
  13. type(sdat.values.username) == "string" and
  14. util.contains(allowed_users, sdat.values.username)
  15. then
  16. return sid, sdat.values
  17. end
  18. return nil
  19. end
  20. function authenticator(validator, accs)
  21. local http = require "luci.http"
  22. local ctrl = require "luci.controller.rpc"
  23. local auth = http.formvalue("auth", true) or http.getcookie("sysauth")
  24. if auth then -- if authentication token was given
  25. local sid, sdat = ctrl.session_retrieve(auth, accs)
  26. if sdat then -- if given token is valid
  27. return sdat.username, sid
  28. end
  29. http.status(403, "Forbidden")
  30. end
  31. end
  32. function index()
  33. local ctrl = require "luci.controller.rpc"
  34. local rpc = node("rpc")
  35. rpc.sysauth = "root"
  36. rpc.sysauth_authenticator = ctrl.authenticator
  37. rpc.notemplate = true
  38. entry({"rpc", "uci"}, call("rpc_uci"))
  39. entry({"rpc", "fs"}, call("rpc_fs"))
  40. entry({"rpc", "sys"}, call("rpc_sys"))
  41. entry({"rpc", "ipkg"}, call("rpc_ipkg"))
  42. entry({"rpc", "ip"}, call("rpc_ip"))
  43. entry({"rpc", "auth"}, call("rpc_auth")).sysauth = false
  44. end
  45. function rpc_auth()
  46. local ctrl = require "luci.controller.rpc"
  47. local jsonrpc = require "luci.jsonrpc"
  48. local http = require "luci.http"
  49. local sys = require "luci.sys"
  50. local ltn12 = require "luci.ltn12"
  51. local util = require "luci.util"
  52. local server = {}
  53. server.challenge = function(user, pass)
  54. local config = require "luci.config"
  55. local login = util.ubus("session", "login", {
  56. username = user,
  57. password = pass,
  58. timeout = tonumber(config.sauth.sessiontime)
  59. })
  60. if type(login) == "table" and
  61. type(login.ubus_rpc_session) == "string"
  62. then
  63. util.ubus("session", "set", {
  64. ubus_rpc_session = login.ubus_rpc_session,
  65. values = {
  66. token = sys.uniqueid(16)
  67. }
  68. })
  69. local sid, sdat = ctrl.session_retrieve(login.ubus_rpc_session, { user })
  70. if sdat then
  71. return {
  72. sid = sid,
  73. token = sdat.token
  74. }
  75. end
  76. end
  77. return nil
  78. end
  79. server.login = function(...)
  80. local challenge = server.challenge(...)
  81. if challenge then
  82. http.header("Set-Cookie", 'sysauth=%s; path=%s' %{
  83. challenge.sid,
  84. http.getenv("SCRIPT_NAME")
  85. })
  86. return challenge.sid
  87. end
  88. end
  89. http.prepare_content("application/json")
  90. ltn12.pump.all(jsonrpc.handle(server, http.source()), http.write)
  91. end
  92. function rpc_uci()
  93. if not pcall(require, "luci.model.uci") then
  94. luci.http.status(404, "Not Found")
  95. return nil
  96. end
  97. local uci = require "luci.jsonrpcbind.uci"
  98. local jsonrpc = require "luci.jsonrpc"
  99. local http = require "luci.http"
  100. local ltn12 = require "luci.ltn12"
  101. http.prepare_content("application/json")
  102. ltn12.pump.all(jsonrpc.handle(uci, http.source()), http.write)
  103. end
  104. function rpc_fs()
  105. local util = require "luci.util"
  106. local io = require "io"
  107. local fs2 = util.clone(require "nixio.fs")
  108. local jsonrpc = require "luci.jsonrpc"
  109. local http = require "luci.http"
  110. local ltn12 = require "luci.ltn12"
  111. function fs2.readfile(filename)
  112. local stat, mime = pcall(require, "mime")
  113. if not stat then
  114. error("Base64 support not available. Please install LuaSocket.")
  115. end
  116. local fp = io.open(filename)
  117. if not fp then
  118. return nil
  119. end
  120. local output = {}
  121. local sink = ltn12.sink.table(output)
  122. local source = ltn12.source.chain(ltn12.source.file(fp), mime.encode("base64"))
  123. return ltn12.pump.all(source, sink) and table.concat(output)
  124. end
  125. function fs2.writefile(filename, data)
  126. local stat, mime = pcall(require, "mime")
  127. if not stat then
  128. error("Base64 support not available. Please install LuaSocket.")
  129. end
  130. local file = io.open(filename, "w")
  131. local sink = file and ltn12.sink.chain(mime.decode("base64"), ltn12.sink.file(file))
  132. return sink and ltn12.pump.all(ltn12.source.string(data), sink) or false
  133. end
  134. http.prepare_content("application/json")
  135. ltn12.pump.all(jsonrpc.handle(fs2, http.source()), http.write)
  136. end
  137. function rpc_sys()
  138. local util = require "luci.util"
  139. local sys = require "luci.sys"
  140. local jsonrpc = require "luci.jsonrpc"
  141. local http = require "luci.http"
  142. local ltn12 = require "luci.ltn12"
  143. local sys2 = util.clone(sys)
  144. sys2.net = util.clone(sys.net)
  145. sys2.wifi = util.clone(sys.wifi)
  146. function sys2.wifi.getiwinfo(ifname, operation)
  147. local iw = sys.wifi.getiwinfo(ifname)
  148. if iw then
  149. if operation then
  150. assert(type(iwinfo[iw.type][operation]) == "function")
  151. return iw[operation]
  152. end
  153. local n, f
  154. local rv = { ifname = ifname }
  155. for n, f in pairs(iwinfo[iw.type]) do
  156. if type(f) == "function" and
  157. n ~= "scanlist" and n ~= "countrylist"
  158. then
  159. rv[n] = iw[n]
  160. end
  161. end
  162. return rv
  163. end
  164. return nil
  165. end
  166. http.prepare_content("application/json")
  167. ltn12.pump.all(jsonrpc.handle(sys2, http.source()), http.write)
  168. end
  169. function rpc_ipkg()
  170. if not pcall(require, "luci.model.ipkg") then
  171. luci.http.status(404, "Not Found")
  172. return nil
  173. end
  174. local ipkg = require "luci.model.ipkg"
  175. local jsonrpc = require "luci.jsonrpc"
  176. local http = require "luci.http"
  177. local ltn12 = require "luci.ltn12"
  178. http.prepare_content("application/json")
  179. ltn12.pump.all(jsonrpc.handle(ipkg, http.source()), http.write)
  180. end
  181. function rpc_ip()
  182. if not pcall(require, "luci.ip") then
  183. luci.http.status(404, "Not Found")
  184. return nil
  185. end
  186. local util = require "luci.util"
  187. local ip = require "luci.ip"
  188. local jsonrpc = require "luci.jsonrpc"
  189. local http = require "luci.http"
  190. local ltn12 = require "luci.ltn12"
  191. local ip2 = util.clone(ip)
  192. local _, n
  193. for _, n in ipairs({ "new", "IPv4", "IPv6", "MAC" }) do
  194. ip2[n] = function(address, netmask, operation, argument)
  195. local cidr = ip[n](address, netmask)
  196. if cidr and operation then
  197. assert(type(cidr[operation]) == "function")
  198. local cidr2 = cidr[operation](cidr, argument)
  199. return (type(cidr2) == "userdata") and cidr2:string() or cidr2
  200. end
  201. return (type(cidr) == "userdata") and cidr:string() or cidr
  202. end
  203. end
  204. http.prepare_content("application/json")
  205. ltn12.pump.all(jsonrpc.handle(ip2, http.source()), http.write)
  206. end