diff options
Diffstat (limited to 'libs')
20 files changed, 1204 insertions, 102 deletions
diff --git a/libs/luci-lib-httpclient/luasrc/httpclient.lua b/libs/luci-lib-httpclient/luasrc/httpclient.lua index 3e8d7277d7..79ce41294c 100644 --- a/libs/luci-lib-httpclient/luasrc/httpclient.lua +++ b/libs/luci-lib-httpclient/luasrc/httpclient.lua @@ -9,9 +9,10 @@ local util = require "luci.util" local table = require "table" local http = require "luci.http" local date = require "luci.http.date" +local ip = require "luci.ip" -local type, pairs, ipairs, tonumber = type, pairs, ipairs, tonumber -local unpack = unpack +local type, pairs, ipairs, tonumber, tostring = type, pairs, ipairs, tonumber, tostring +local unpack, string = unpack, string module "luci.httpclient" @@ -25,7 +26,7 @@ function chunksource(sock, buffer) if not newblock then return nil, code end - buffer = buffer .. newblock + buffer = buffer .. newblock _, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n") end count = tonumber(count, 16) @@ -62,17 +63,17 @@ end function request_to_buffer(uri, options) local source, code, msg = request_to_source(uri, options) local output = {} - + if not source then return nil, code, msg end - + source, code = ltn12.pump.all(source, (ltn12.sink.table(output))) - + if not source then return nil, code end - + return table.concat(output) end @@ -83,7 +84,7 @@ function request_to_source(uri, options) elseif status ~= 200 and status ~= 206 then return nil, status, buffer end - + if response.headers["Transfer-Encoding"] == "chunked" then return chunksource(sock, buffer) else @@ -91,67 +92,115 @@ function request_to_source(uri, options) end end +function parse_url(uri) + local url, rest, tmp = {}, nil, nil + + url.scheme, rest = uri:match("^(%w+)://(.+)$") + if not (url.scheme and rest) then + return nil + end + + url.auth, tmp = rest:match("^([^@]+)@(.+)$") + if url.auth and tmp then + rest = tmp + end + + url.host, tmp = rest:match("^%[([0-9a-fA-F:]+)%](.*)$") + if url.host and tmp then + url.ip6addr = ip.IPv6(url.host) + if not url.ip6addr then + return nil + end + url.host = string.format("[%s]", url.ip6addr:string()) + rest = tmp + else + url.host, tmp = rest:match("^(%d+%.%d+%.%d+%.%d+)(.*)$") + if url.host and tmp then + url.ipaddr = ip.IPv4(url.host) + if not url.ipaddr then + return nil + end + url.host = url.ipaddr:string() + rest = tmp + else + url.host, tmp = rest:match("^([0-9a-zA-Z%.%-]+)(.*)$") + if url.host and tmp then + rest = tmp + else + return nil + end + end + end + + url.port, tmp = rest:match("^:(%d+)(.*)$") + if url.port and tmp then + url.port = tonumber(url.port) + rest = tmp + if url.port < 1 or url.port > 65535 then + return nil + end + end + + if url.scheme == "http" then + url.port = url.port or 80 + url.default_port = (url.port == 80) + elseif url.scheme == "https" then + url.port = url.port or 443 + url.default_port = (url.port == 443) + end + + if rest == "" then + url.path = "/" + else + url.path = rest + end + + return url +end + -- -- GET HTTP-resource -- function request_raw(uri, options) options = options or {} - local pr, auth, host, port, path if options.params then uri = uri .. '?' .. http.urlencode_params(options.params) end - if uri:find("%[") then - if uri:find("@") then - pr, auth, host, port, path = uri:match("(%w+)://(.+)@(%b[]):?([0-9]*)(.*)") - host = host:sub(2,-2) - else - pr, host, port, path = uri:match("(%w+)://(%b[]):?([0-9]*)(.*)") - host = host:sub(2,-2) - end - else - if uri:find("@") then - pr, auth, host, port, path = - uri:match("(%w+)://(.+)@([%w-.]+):?([0-9]*)(.*)") - else - pr, host, port, path = uri:match("(%w+)://([%w-.]+):?([0-9]*)(.*)") - end - end + local url = parse_url(uri) - if not host then + if not url then return nil, -1, "unable to parse URI" end - - if pr ~= "http" and pr ~= "https" then + + if url.scheme ~= "http" and url.scheme ~= "https" then return nil, -2, "protocol not supported" end - - port = #port > 0 and port or (pr == "https" and 443 or 80) - path = #path > 0 and path or "/" - + options.depth = options.depth or 10 local headers = options.headers or {} local protocol = options.protocol or "HTTP/1.1" headers["User-Agent"] = headers["User-Agent"] or "LuCI httpclient 0.1" - + if headers.Connection == nil then headers.Connection = "close" end - - if auth and not headers.Authorization then - headers.Authorization = "Basic " .. nixio.bin.b64encode(auth) + + if url.auth and not headers.Authorization then + headers.Authorization = "Basic " .. nixio.bin.b64encode(url.auth) end - local sock, code, msg = nixio.connect(host, port) + local addr = tostring(url.ip6addr or url.ipaddr or url.host) + local sock, code, msg = nixio.connect(addr, url.port) if not sock then return nil, code, msg end - + sock:setsockopt("socket", "sndtimeo", options.sndtimeo or 15) sock:setsockopt("socket", "rcvtimeo", options.rcvtimeo or 15) - - if pr == "https" then + + if url.scheme == "https" then local tls = options.tls_context or nixio.tls() sock = tls:create(sock) local stat, code, error = sock:connect() @@ -160,11 +209,12 @@ function request_raw(uri, options) end end - -- Pre assemble fixes + -- Pre assemble fixes if protocol == "HTTP/1.1" then - headers.Host = headers.Host or host + headers.Host = headers.Host or + (url.default_port and url.host or string.format("%s:%d", url.host, url.port)) end - + if type(options.body) == "table" then options.body = http.urlencode_params(options.body) end @@ -175,7 +225,7 @@ function request_raw(uri, options) "application/x-www-form-urlencoded" options.method = options.method or "POST" end - + if type(options.body) == "function" then options.method = options.method or "POST" end @@ -185,12 +235,12 @@ function request_raw(uri, options) for _, c in ipairs(options.cookies) do local cdo = c.flags.domain local cpa = c.flags.path - if (cdo == host or cdo == "."..host or host:sub(-#cdo) == cdo) - and (cpa == path or cpa == "/" or cpa .. "/" == path:sub(#cpa+1)) - and (not c.flags.secure or pr == "https") + if (cdo == url.host or cdo == "."..url.host or url.host:sub(-#cdo) == cdo) + and (cpa == url.path or cpa == "/" or cpa .. "/" == url.path:sub(#cpa+1)) + and (not c.flags.secure or url.scheme == "https") then cookiedata[#cookiedata+1] = c.key .. "=" .. c.value - end + end end if headers["Cookie"] then headers["Cookie"] = headers["Cookie"] .. "; " .. table.concat(cookiedata, "; ") @@ -200,8 +250,8 @@ function request_raw(uri, options) end -- Assemble message - local message = {(options.method or "GET") .. " " .. path .. " " .. protocol} - + local message = {(options.method or "GET") .. " " .. url.path .. " " .. protocol} + for k, v in pairs(headers) do if type(v) == "string" or type(v) == "number" then message[#message+1] = k .. ": " .. v @@ -214,10 +264,10 @@ function request_raw(uri, options) message[#message+1] = "" message[#message+1] = "" - + -- Send request sock:sendall(table.concat(message, "\r\n")) - + if type(options.body) == "string" then sock:sendall(options.body) elseif type(options.body) == "function" then @@ -227,27 +277,27 @@ function request_raw(uri, options) return unpack(res) end end - + -- Create source and fetch response local linesrc = sock:linesource() local line, code, error = linesrc() - + if not line then sock:close() return nil, code, error end - + local protocol, status, msg = line:match("^([%w./]+) ([0-9]+) (.*)") - + if not protocol then sock:close() return nil, -3, "invalid response magic: " .. line end - + local response = { status = line, headers = {}, code = 0, cookies = {}, uri = uri } - + line = linesrc() while line and line ~= "" do local key, val = line:match("^([%w-]+)%s?:%s?(.*)") @@ -262,32 +312,32 @@ function request_raw(uri, options) end line = linesrc() end - + if not line then sock:close() return nil, -4, "protocol error" end - + -- Parse cookies if response.headers["Set-Cookie"] then local cookies = response.headers["Set-Cookie"] for _, c in ipairs(type(cookies) == "table" and cookies or {cookies}) do local cobj = cookie_parse(c) - cobj.flags.path = cobj.flags.path or path:match("(/.*)/?[^/]*") + cobj.flags.path = cobj.flags.path or url.path:match("(/.*)/?[^/]*") if not cobj.flags.domain or cobj.flags.domain == "" then - cobj.flags.domain = host + cobj.flags.domain = url.host response.cookies[#response.cookies+1] = cobj else local hprt, cprt = {}, {} - + -- Split hostnames and save them in reverse order - for part in host:gmatch("[^.]*") do + for part in url.host:gmatch("[^.]*") do table.insert(hprt, 1, part) end for part in cobj.flags.domain:gmatch("[^.]*") do table.insert(cprt, 1, part) end - + local valid = true for i, part in ipairs(cprt) do -- If parts are different and no wildcard @@ -309,8 +359,8 @@ function request_raw(uri, options) end end end - - -- Follow + + -- Follow response.code = tonumber(status) if response.code and options.depth > 0 then if (response.code == 301 or response.code == 302 or response.code == 307) @@ -319,20 +369,21 @@ function request_raw(uri, options) if not nuri then return nil, -5, "invalid reference" end - if not nuri:find("https?://") then - nuri = pr .. "://" .. host .. ":" .. port .. nuri + if not nuri:match("^%w+://") then + nuri = url.default_port and string.format("%s://%s%s", url.scheme, url.host, nuri) + or string.format("%s://%s:%d%s", url.scheme, url.host, url.port, nuri) end - + options.depth = options.depth - 1 if options.headers then options.headers.Host = nil end sock:close() - + return request_raw(nuri, options) end end - + return response.code, response, linesrc(true)..sock:readall(), sock end diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc b/libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc index 7751e2baf4..9c7f01aedf 100644 --- a/libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc +++ b/libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc @@ -7,7 +7,7 @@ vice versa. module "luci.http.mime" ---[[ -MIME mapping table containg extension - mimetype relations. +MIME mapping table containing extension - mimetype relations. @class table ]] diff --git a/libs/luci-lib-ip/src/ip.luadoc b/libs/luci-lib-ip/src/ip.luadoc index b1ecae1453..a2df96cdb5 100644 --- a/libs/luci-lib-ip/src/ip.luadoc +++ b/libs/luci-lib-ip/src/ip.luadoc @@ -283,7 +283,7 @@ Fetch all routes, optionally matching the given criteria. @sort 9 @name routes @param filter <p>Table containing one or more of the possible filter -critera described below (optional)</p><table> +criteria described below (optional)</p><table> <tr><th>Field</th><th>Description</th></tr> <tr><td>`family`</td><td> Number describing the address family to return - `4` selects @@ -363,7 +363,7 @@ Fetches entries from the IPv4 ARP and IPv6 neighbour kernel table @sort 10 @name neighbors @param filter <p>Table containing one or more of the possible filter -critera described below (optional)</p><table> +criteria described below (optional)</p><table> <tr><th>Field</th><th>Description</th></tr> <tr><td>`family`</td><td> Number describing the address family to return - `4` selects @@ -652,7 +652,7 @@ are considered lower than MAC addresses</li> @class function @sort 10 @name cidr.lower -@param addr A `luci.ip.cidr` instance or a string convertable by +@param addr A `luci.ip.cidr` instance or a string convertible by `luci.ip.new()` to compare against. @return `true` if this CIDR is lower than the given address, else `false`. @@ -676,7 +676,7 @@ are considered lower than MAC addresses</li> @class function @sort 11 @name cidr.higher -@param addr A `luci.ip.cidr` instance or a string convertable by +@param addr A `luci.ip.cidr` instance or a string convertible by `luci.ip.new()` to compare against. @return `true` if this CIDR is higher than the given address, else `false`. @@ -696,7 +696,7 @@ Checks whether this CIDR instance is equal to the given argument. @class function @sort 12 @name cidr.equal -@param addr A `luci.ip.cidr` instance or a string convertable by +@param addr A `luci.ip.cidr` instance or a string convertible by `luci.ip.new()` to compare against. @return `true` if this CIDR is equal to the given address, else `false`. @@ -877,7 +877,7 @@ Test whether CIDR contains given range. @class function @sort 21 @name cidr.contains -@param addr A `luci.ip.cidr` instance or a string convertable by +@param addr A `luci.ip.cidr` instance or a string convertible by `luci.ip.new()` to test. @return `true` if this instance fully contains the given address else `false`. @@ -903,12 +903,12 @@ address space, the result is set to the highest possible address. @sort 22 @name cidr.add @param amount A numeric value between 0 and 0xFFFFFFFF, a - `luci.ip.cidr` instance or a string convertable by + `luci.ip.cidr` instance or a string convertible by `luci.ip.new()`. @param inplace If `true`, modify this instance instead of returning a new derived CIDR instance. @return <ul> - <li>When adding inplace: Return `true` if the addition succeded + <li>When adding inplace: Return `true` if the addition succeeded or `false` when the addition overflowed.</li> <li>When deriving new CIDR: Return new instance representing the value of this instance plus the added amount or the highest possible address if @@ -952,7 +952,7 @@ possible address is returned. @sort 23 @name cidr.sub @param amount A numeric value between 0 and 0xFFFFFFFF, a - `luci.ip.cidr` instance or a string convertable by + `luci.ip.cidr` instance or a string convertible by `luci.ip.new()`. @param inplace If `true`, modify this instance instead of returning a new derived CIDR instance. diff --git a/libs/luci-lib-ipkg/Makefile b/libs/luci-lib-ipkg/Makefile new file mode 100644 index 0000000000..52fcf6fe82 --- /dev/null +++ b/libs/luci-lib-ipkg/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (C) 2018 Jo-Philipp Wich <jo@mein.io> +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Legacy opkg interface class +LUCI_DEPENDS:=+luci-base + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/libs/luci-lib-ipkg/luasrc/model/ipkg.lua b/libs/luci-lib-ipkg/luasrc/model/ipkg.lua new file mode 100644 index 0000000000..e27ea52895 --- /dev/null +++ b/libs/luci-lib-ipkg/luasrc/model/ipkg.lua @@ -0,0 +1,247 @@ +-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org> +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Licensed to the public under the Apache License 2.0. + +local os = require "os" +local io = require "io" +local fs = require "nixio.fs" +local util = require "luci.util" + +local type = type +local pairs = pairs +local error = error +local table = table + +local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase" +local icfg = "/etc/opkg.conf" + +module "luci.model.ipkg" + + +-- Internal action function +local function _action(cmd, ...) + local cmdline = { ipkg, cmd } + + local k, v + for k, v in pairs({...}) do + cmdline[#cmdline+1] = util.shellquote(v) + end + + local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ") + local r = os.execute(c) + local e = fs.readfile("/tmp/opkg.stderr") + local o = fs.readfile("/tmp/opkg.stdout") + + fs.unlink("/tmp/opkg.stderr") + fs.unlink("/tmp/opkg.stdout") + + return r, o or "", e or "" +end + +-- Internal parser function +local function _parselist(rawdata) + if type(rawdata) ~= "function" then + error("OPKG: Invalid rawdata given") + end + + local data = {} + local c = {} + local l = nil + + for line in rawdata do + if line:sub(1, 1) ~= " " then + local key, val = line:match("(.-): ?(.*)%s*") + + if key and val then + if key == "Package" then + c = {Package = val} + data[val] = c + elseif key == "Status" then + c.Status = {} + for j in val:gmatch("([^ ]+)") do + c.Status[j] = true + end + else + c[key] = val + end + l = key + end + else + -- Multi-line field + c[l] = c[l] .. "\n" .. line + end + end + + return data +end + +-- Internal lookup function +local function _lookup(cmd, pkg) + local cmdline = { ipkg, cmd } + if pkg then + cmdline[#cmdline+1] = util.shellquote(pkg) + end + + -- OPKG sometimes kills the whole machine because it sucks + -- Therefore we have to use a sucky approach too and use + -- tmpfiles instead of directly reading the output + local tmpfile = os.tmpname() + os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile }) + + local data = _parselist(io.lines(tmpfile)) + os.remove(tmpfile) + return data +end + + +function info(pkg) + return _lookup("info", pkg) +end + +function status(pkg) + return _lookup("status", pkg) +end + +function install(...) + return _action("install", ...) +end + +function installed(pkg) + local p = status(pkg)[pkg] + return (p and p.Status and p.Status.installed) +end + +function remove(...) + return _action("remove", ...) +end + +function update() + return _action("update") +end + +function upgrade() + return _action("upgrade") +end + +-- List helper +local function _list(action, pat, cb) + local cmdline = { ipkg, action } + if pat then + cmdline[#cmdline+1] = util.shellquote(pat) + end + + local fd = io.popen(table.concat(cmdline, " ")) + if fd then + local name, version, sz, desc + while true do + local line = fd:read("*l") + if not line then break end + + name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)") + + if not name then + name, version, sz = line:match("^(.-) %- (.-) %- (.+)") + desc = "" + end + + if name and version then + if #version > 26 then + version = version:sub(1,21) .. ".." .. version:sub(-3,-1) + end + + cb(name, version, sz, desc) + end + + name = nil + version = nil + sz = nil + desc = nil + end + + fd:close() + end +end + +function list_all(pat, cb) + _list("list --size", pat, cb) +end + +function list_installed(pat, cb) + _list("list_installed --size", pat, cb) +end + +function find(pat, cb) + _list("find --size", pat, cb) +end + + +function overlay_root() + local od = "/" + local fd = io.open(icfg, "r") + + if fd then + local ln + + repeat + ln = fd:read("*l") + if ln and ln:match("^%s*option%s+overlay_root%s+") then + od = ln:match("^%s*option%s+overlay_root%s+(%S+)") + + local s = fs.stat(od) + if not s or s.type ~= "dir" then + od = "/" + end + + break + end + until not ln + + fd:close() + end + + return od +end + +function compare_versions(ver1, comp, ver2) + if not ver1 or not ver2 + or not comp or not (#comp > 0) then + error("Invalid parameters") + return nil + end + -- correct compare string + if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~=" + elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<=" + elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">=" + elseif comp == "=" or comp == "==" then comp = "==" + elseif comp == "<<" then comp = "<" + elseif comp == ">>" then comp = ">" + else + error("Invalid compare string") + return nil + end + + local av1 = util.split(ver1, "[%.%-]", nil, true) + local av2 = util.split(ver2, "[%.%-]", nil, true) + + local max = table.getn(av1) + if (table.getn(av1) < table.getn(av2)) then + max = table.getn(av2) + end + + for i = 1, max, 1 do + local s1 = av1[i] or "" + local s2 = av2[i] or "" + + -- first "not equal" found return true + if comp == "~=" and (s1 ~= s2) then return true end + -- first "lower" found return true + if (comp == "<" or comp == "<=") and (s1 < s2) then return true end + -- first "greater" found return true + if (comp == ">" or comp == ">=") and (s1 > s2) then return true end + -- not equal then return false + if (s1 ~= s2) then return false end + end + + -- all equal and not compare greater or lower then true + return not (comp == "<" or comp == ">") +end diff --git a/libs/luci-lib-ipkg/luasrc/model/ipkg.luadoc b/libs/luci-lib-ipkg/luasrc/model/ipkg.luadoc new file mode 100644 index 0000000000..4e1548dda6 --- /dev/null +++ b/libs/luci-lib-ipkg/luasrc/model/ipkg.luadoc @@ -0,0 +1,125 @@ +---[[ +LuCI OPKG call abstraction library +]] +module "luci.model.ipkg" + +---[[ +Return information about installed and available packages. + +@class function +@name info +@param pkg Limit output to a (set of) packages +@return Table containing package information +]] + +---[[ +Return the package status of one or more packages. + +@class function +@name status +@param pkg Limit output to a (set of) packages +@return Table containing package status information +]] + +---[[ +Install one or more packages. + +@class function +@name install +@param ... List of packages to install +@return Boolean indicating the status of the action +@return OPKG return code, STDOUT and STDERR +]] + +---[[ +Determine whether a given package is installed. + +@class function +@name installed +@param pkg Package +@return Boolean +]] + +---[[ +Remove one or more packages. + +@class function +@name remove +@param ... List of packages to install +@return Boolean indicating the status of the action +@return OPKG return code, STDOUT and STDERR +]] + +---[[ +Update package lists. + +@class function +@name update +@return Boolean indicating the status of the action +@return OPKG return code, STDOUT and STDERR +]] + +---[[ +Upgrades all installed packages. + +@class function +@name upgrade +@return Boolean indicating the status of the action +@return OPKG return code, STDOUT and STDERR +]] + +---[[ +List all packages known to opkg. + +@class function +@name list_all +@param pat Only find packages matching this pattern, nil lists all packages +@param cb Callback function invoked for each package, receives name, version and description as arguments +@return nothing +]] + +---[[ +List installed packages. + +@class function +@name list_installed +@param pat Only find packages matching this pattern, nil lists all packages +@param cb Callback function invoked for each package, receives name, version and description as arguments +@return nothing +]] + +---[[ +Find packages that match the given pattern. + +@class function +@name find +@param pat Find packages whose names or descriptions match this pattern, nil results in zero results +@param cb Callback function invoked for each patckage, receives name, version and description as arguments +@return nothing +]] + +---[[ +Determines the overlay root used by opkg. + +@class function +@name overlay_root +@return String containing the directory path of the overlay root. +]] + +---[[ +lua version of opkg compare-versions + +@class function +@name compare_versions +@param ver1 string version 1 +@param ver2 string version 2 +@param comp string compare versions using + "<=" or "<" lower-equal + ">" or ">=" greater-equal + "=" equal + "<<" lower + ">>" greater + "~=" not equal +@return Boolean indicating the status of the compare +]] + diff --git a/libs/luci-lib-iptparser/Makefile b/libs/luci-lib-iptparser/Makefile new file mode 100644 index 0000000000..06748adbfc --- /dev/null +++ b/libs/luci-lib-iptparser/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (C) 2018 The LuCI Team <luci@lists.subsignal.org> +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Iptables listing parser class +LUCI_DEPENDS:=+luci-base + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/libs/luci-lib-iptparser/luasrc/sys/iptparser.lua b/libs/luci-lib-iptparser/luasrc/sys/iptparser.lua new file mode 100644 index 0000000000..7ff665e7af --- /dev/null +++ b/libs/luci-lib-iptparser/luasrc/sys/iptparser.lua @@ -0,0 +1,374 @@ +--[[ + +Iptables parser and query library +(c) 2008-2009 Jo-Philipp Wich <jow@openwrt.org> +(c) 2008-2009 Steven Barth <steven@midlink.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +]]-- + +local luci = {} +luci.util = require "luci.util" +luci.sys = require "luci.sys" +luci.ip = require "luci.ip" + +local pcall = pcall +local io = require "io" +local tonumber, ipairs, table = tonumber, ipairs, table + +module("luci.sys.iptparser") + +IptParser = luci.util.class() + +function IptParser.__init__( self, family ) + self._family = (tonumber(family) == 6) and 6 or 4 + self._rules = { } + self._chains = { } + self._tables = { } + + local t = self._tables + local s = self:_supported_tables(self._family) + + if s.filter then t[#t+1] = "filter" end + if s.nat then t[#t+1] = "nat" end + if s.mangle then t[#t+1] = "mangle" end + if s.raw then t[#t+1] = "raw" end + + if self._family == 4 then + self._nulladdr = "0.0.0.0/0" + self._command = "iptables -t %s --line-numbers -nxvL" + else + self._nulladdr = "::/0" + self._command = "ip6tables -t %s --line-numbers -nxvL" + end + + self:_parse_rules() +end + +function IptParser._supported_tables( self, family ) + local tables = { } + local ok, lines = pcall(io.lines, + (family == 6) and "/proc/net/ip6_tables_names" + or "/proc/net/ip_tables_names") + + if ok and lines then + local line + for line in lines do + tables[line] = true + end + end + + return tables +end + +-- search criteria as only argument. If args is nil or an empty table then all +-- rules will be returned. +-- +-- The following keys in the args table are recognized: +-- <ul> +-- <li> table - Match rules that are located within the given table +-- <li> chain - Match rules that are located within the given chain +-- <li> target - Match rules with the given target +-- <li> protocol - Match rules that match the given protocol, rules with +-- protocol "all" are always matched +-- <li> source - Match rules with the given source, rules with source +-- "0.0.0.0/0" (::/0) are always matched +-- <li> destination - Match rules with the given destination, rules with +-- destination "0.0.0.0/0" (::/0) are always matched +-- <li> inputif - Match rules with the given input interface, rules +-- with input interface "*" (=all) are always matched +-- <li> outputif - Match rules with the given output interface, rules +-- with output interface "*" (=all) are always matched +-- <li> flags - Match rules that match the given flags, current +-- supported values are "-f" (--fragment) +-- and "!f" (! --fragment) +-- <li> options - Match rules containing all given options +-- </ul> +-- The return value is a list of tables representing the matched rules. +-- Each rule table contains the following fields: +-- <ul> +-- <li> index - The index number of the rule +-- <li> table - The table where the rule is located, can be one +-- of "filter", "nat" or "mangle" +-- <li> chain - The chain where the rule is located, e.g. "INPUT" +-- or "postrouting_wan" +-- <li> target - The rule target, e.g. "REJECT" or "DROP" +-- <li> protocol The matching protocols, e.g. "all" or "tcp" +-- <li> flags - Special rule options ("--", "-f" or "!f") +-- <li> inputif - Input interface of the rule, e.g. "eth0.0" +-- or "*" for all interfaces +-- <li> outputif - Output interface of the rule,e.g. "eth0.0" +-- or "*" for all interfaces +-- <li> source - The source ip range, e.g. "0.0.0.0/0" (::/0) +-- <li> destination - The destination ip range, e.g. "0.0.0.0/0" (::/0) +-- <li> options - A list of specific options of the rule, +-- e.g. { "reject-with", "tcp-reset" } +-- <li> packets - The number of packets matched by the rule +-- <li> bytes - The number of total bytes matched by the rule +-- </ul> +-- Example: +-- <pre> +-- ip = luci.sys.iptparser.IptParser() +-- result = ip.find( { +-- target="REJECT", +-- protocol="tcp", +-- options={ "reject-with", "tcp-reset" } +-- } ) +-- </pre> +-- This will match all rules with target "-j REJECT", +-- protocol "-p tcp" (or "-p all") +-- and the option "--reject-with tcp-reset". +function IptParser.find( self, args ) + + local args = args or { } + local rv = { } + + args.source = args.source and self:_parse_addr(args.source) + args.destination = args.destination and self:_parse_addr(args.destination) + + for i, rule in ipairs(self._rules) do + local match = true + + -- match table + if not ( not args.table or args.table:lower() == rule.table ) then + match = false + end + + -- match chain + if not ( match == true and ( + not args.chain or args.chain == rule.chain + ) ) then + match = false + end + + -- match target + if not ( match == true and ( + not args.target or args.target == rule.target + ) ) then + match = false + end + + -- match protocol + if not ( match == true and ( + not args.protocol or rule.protocol == "all" or + args.protocol:lower() == rule.protocol + ) ) then + match = false + end + + -- match source + if not ( match == true and ( + not args.source or rule.source == self._nulladdr or + self:_parse_addr(rule.source):contains(args.source) + ) ) then + match = false + end + + -- match destination + if not ( match == true and ( + not args.destination or rule.destination == self._nulladdr or + self:_parse_addr(rule.destination):contains(args.destination) + ) ) then + match = false + end + + -- match input interface + if not ( match == true and ( + not args.inputif or rule.inputif == "*" or + args.inputif == rule.inputif + ) ) then + match = false + end + + -- match output interface + if not ( match == true and ( + not args.outputif or rule.outputif == "*" or + args.outputif == rule.outputif + ) ) then + match = false + end + + -- match flags (the "opt" column) + if not ( match == true and ( + not args.flags or rule.flags == args.flags + ) ) then + match = false + end + + -- match specific options + if not ( match == true and ( + not args.options or + self:_match_options( rule.options, args.options ) + ) ) then + match = false + end + + -- insert match + if match == true then + rv[#rv+1] = rule + end + end + + return rv +end + + +-- through external commands. +function IptParser.resync( self ) + self._rules = { } + self._chain = nil + self:_parse_rules() +end + + +function IptParser.tables( self ) + return self._tables +end + + +function IptParser.chains( self, table ) + local lookup = { } + local chains = { } + for _, r in ipairs(self:find({table=table})) do + if not lookup[r.chain] then + lookup[r.chain] = true + chains[#chains+1] = r.chain + end + end + return chains +end + + +-- and "rules". The "rules" field is a table of rule tables. +function IptParser.chain( self, table, chain ) + return self._chains[table:lower()] and self._chains[table:lower()][chain] +end + + +function IptParser.is_custom_target( self, target ) + for _, r in ipairs(self._rules) do + if r.chain == target then + return true + end + end + return false +end + + +-- [internal] Parse address according to family. +function IptParser._parse_addr( self, addr ) + if self._family == 4 then + return luci.ip.IPv4(addr) + else + return luci.ip.IPv6(addr) + end +end + +-- [internal] Parse iptables output from all tables. +function IptParser._parse_rules( self ) + + for i, tbl in ipairs(self._tables) do + + self._chains[tbl] = { } + + for i, rule in ipairs(luci.util.execl(self._command % tbl)) do + + if rule:find( "^Chain " ) == 1 then + + local crefs + local cname, cpol, cpkt, cbytes = rule:match( + "^Chain ([^%s]*) %(policy (%w+) " .. + "(%d+) packets, (%d+) bytes%)" + ) + + if not cname then + cname, crefs = rule:match( + "^Chain ([^%s]*) %((%d+) references%)" + ) + end + + self._chain = cname + self._chains[tbl][cname] = { + policy = cpol, + packets = tonumber(cpkt or 0), + bytes = tonumber(cbytes or 0), + references = tonumber(crefs or 0), + rules = { } + } + + else + if rule:find("%d") == 1 then + + local rule_parts = luci.util.split( rule, "%s+", nil, true ) + local rule_details = { } + + -- cope with rules that have no target assigned + if rule:match("^%d+%s+%d+%s+%d+%s%s") then + table.insert(rule_parts, 4, nil) + end + + -- ip6tables opt column is usually zero-width + if self._family == 6 then + table.insert(rule_parts, 6, "--") + end + + rule_details["table"] = tbl + rule_details["chain"] = self._chain + rule_details["index"] = tonumber(rule_parts[1]) + rule_details["packets"] = tonumber(rule_parts[2]) + rule_details["bytes"] = tonumber(rule_parts[3]) + rule_details["target"] = rule_parts[4] + rule_details["protocol"] = rule_parts[5] + rule_details["flags"] = rule_parts[6] + rule_details["inputif"] = rule_parts[7] + rule_details["outputif"] = rule_parts[8] + rule_details["source"] = rule_parts[9] + rule_details["destination"] = rule_parts[10] + rule_details["options"] = { } + + for i = 11, #rule_parts do + if #rule_parts[i] > 0 then + rule_details["options"][i-10] = rule_parts[i] + end + end + + self._rules[#self._rules+1] = rule_details + + self._chains[tbl][self._chain].rules[ + #self._chains[tbl][self._chain].rules + 1 + ] = rule_details + end + end + end + end + + self._chain = nil +end + + +-- [internal] Return true if optlist1 contains all elements of optlist 2. +-- Return false in all other cases. +function IptParser._match_options( self, o1, o2 ) + + -- construct a hashtable of first options list to speed up lookups + local oh = { } + for i, opt in ipairs( o1 ) do oh[opt] = true end + + -- iterate over second options list + -- each string in o2 must be also present in o1 + -- if o2 contains a string which is not found in o1 then return false + for i, opt in ipairs( o2 ) do + if not oh[opt] then + return false + end + end + + return true +end diff --git a/libs/luci-lib-iptparser/luasrc/sys/iptparser.luadoc b/libs/luci-lib-iptparser/luasrc/sys/iptparser.luadoc new file mode 100644 index 0000000000..071e7d52e4 --- /dev/null +++ b/libs/luci-lib-iptparser/luasrc/sys/iptparser.luadoc @@ -0,0 +1,69 @@ +---[[ +LuCI iptables parser and query library + +@cstyle instance +]] +module "luci.sys.iptparser" + +---[[ +Create a new iptables parser object. + +@class function +@name IptParser +@param family Number specifying the address family. 4 for IPv4, 6 for IPv6 +@return IptParser instance +]] + +---[[ +Find all firewall rules that match the given criteria. Expects a table with + +search criteria as only argument. If args is nil or an empty table then all +rules will be returned. +]] + +---[[ +Rebuild the internal lookup table, for example when rules have changed + +through external commands. +@class function +@name IptParser.resync +@return nothing +]] + +---[[ +Find the names of all tables. + +@class function +@name IptParser.tables +@return Table of table names. +]] + +---[[ +Find the names of all chains within the given table name. + +@class function +@name IptParser.chains +@param table String containing the table name +@return Table of chain names in the order they occur. +]] + +---[[ +Return the given firewall chain within the given table name. + +@class function +@name IptParser.chain +@param table String containing the table name +@param chain String containing the chain name +@return Table containing the fields "policy", "packets", "bytes" +-- and "rules". The "rules" field is a table of rule tables. +]] + +---[[ +Test whether the given target points to a custom chain. + +@class function +@name IptParser.is_custom_target +@param target String containing the target action +@return Boolean indicating whether target is a custom chain. +]] + diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c index ef11101660..9ff8520dbc 100644 --- a/libs/luci-lib-jsonc/src/jsonc.c +++ b/libs/luci-lib-jsonc/src/jsonc.c @@ -27,6 +27,12 @@ limitations under the License. #define LUCI_JSONC "luci.jsonc" #define LUCI_JSONC_PARSER "luci.jsonc.parser" +struct seen { + size_t size; + size_t len; + const void *ptrs[]; +}; + struct json_state { struct json_object *obj; struct json_tokener *tok; @@ -35,6 +41,7 @@ struct json_state { static void _json_to_lua(lua_State *L, struct json_object *obj); static struct json_object * _lua_to_json(lua_State *L, int index); +static struct json_object * _lua_to_json_rec(lua_State *L, int index, struct seen **seen); static int json_new(lua_State *L) { @@ -199,6 +206,9 @@ static int _lua_test_array(lua_State *L, int index) int max = 0; lua_Number idx; + if (!lua_checkstack(L, 2)) + return -1; + lua_pushnil(L); /* check for non-integer keys */ @@ -243,16 +253,54 @@ out: return max; } -static struct json_object * _lua_to_json(lua_State *L, int index) + +static bool visited(struct seen **sp, const void *ptr) { + struct seen *s = *sp; + size_t i; + + if (s->len >= s->size) + { + i = s->size + 10; + s = realloc(*sp, sizeof(struct seen) + sizeof(void *) * i); + + if (!s) + { + if (*sp) + free(*sp); + + *sp = NULL; + return true; + } + + s->size = i; + *sp = s; + } + + for (i = 0; i < s->len; i++) + if (s->ptrs[i] == ptr) + return true; + + s->ptrs[s->len++] = ptr; + return false; +} + +static struct json_object * _lua_to_json_rec(lua_State *L, int index, + struct seen **seen) { lua_Number nd, ni; struct json_object *obj; const char *key; int i, max; + if (index < 0) + index = lua_gettop(L) + index + 1; + switch (lua_type(L, index)) { case LUA_TTABLE: + if (visited(seen, lua_topointer(L, index))) + return NULL; + max = _lua_test_array(L, index); if (max >= 0) @@ -262,12 +310,15 @@ static struct json_object * _lua_to_json(lua_State *L, int index) if (!obj) return NULL; + if (!lua_checkstack(L, 1)) + return NULL; + for (i = 1; i <= max; i++) { lua_rawgeti(L, index, i); json_object_array_put_idx(obj, i - 1, - _lua_to_json(L, lua_gettop(L))); + _lua_to_json_rec(L, -1, seen)); lua_pop(L, 1); } @@ -280,6 +331,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index) if (!obj) return NULL; + if (!lua_checkstack(L, 3)) + return NULL; + lua_pushnil(L); while (lua_next(L, index)) @@ -289,7 +343,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index) if (key) json_object_object_add(obj, key, - _lua_to_json(L, lua_gettop(L) - 1)); + _lua_to_json_rec(L, -2, seen)); lua_pop(L, 2); } @@ -318,6 +372,23 @@ static struct json_object * _lua_to_json(lua_State *L, int index) return NULL; } +static struct json_object * _lua_to_json(lua_State *L, int index) +{ + struct seen *s = calloc(sizeof(struct seen) + sizeof(void *) * 10, 1); + struct json_object *rv; + + if (!s) + return NULL; + + s->size = 10; + + rv = _lua_to_json_rec(L, index, &s); + + free(s); + + return rv; +} + static int json_parse_set(lua_State *L) { struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER); diff --git a/libs/luci-lib-nixio/Makefile b/libs/luci-lib-nixio/Makefile index bec5f83cda..4e501b89ce 100644 --- a/libs/luci-lib-nixio/Makefile +++ b/libs/luci-lib-nixio/Makefile @@ -11,6 +11,44 @@ LUCI_DEPENDS:=+PACKAGE_luci-lib-nixio_openssl:libopenssl +PACKAGE_luci-lib-nixio PKG_LICENSE:=Apache-2.0 +define Package/luci-lib-nixio/config + choice + prompt "TLS Provider" + default PACKAGE_luci-lib-nixio_notls + + config PACKAGE_luci-lib-nixio_notls + bool "Disabled" + + config PACKAGE_luci-lib-nixio_axtls + bool "Builtin (axTLS)" + + config PACKAGE_luci-lib-nixio_cyassl + bool "CyaSSL" + select PACKAGE_libcyassl + + config PACKAGE_luci-lib-nixio_openssl + bool "OpenSSL" + select PACKAGE_libopenssl + endchoice +endef + +NIXIO_TLS:= + +ifneq ($(CONFIG_PACKAGE_luci-lib-nixio_axtls),) + NIXIO_TLS:=axtls +endif + +ifneq ($(CONFIG_PACKAGE_luci-lib-nixio_openssl),) + NIXIO_TLS:=openssl +endif + +ifneq ($(CONFIG_PACKAGE_luci-lib-nixio_cyassl),) + NIXIO_TLS:=cyassl + LUCI_CFLAGS+=-I$(STAGING_DIR)/usr/include/cyassl +endif + +MAKE_VARS += NIXIO_TLS="$(NIXIO_TLS)" + include ../../luci.mk # call BuildPackage - OpenWrt buildroot signature diff --git a/libs/luci-lib-nixio/docsrc/CHANGELOG.lua b/libs/luci-lib-nixio/docsrc/CHANGELOG.lua index aa31841402..8c9260317b 100644 --- a/libs/luci-lib-nixio/docsrc/CHANGELOG.lua +++ b/libs/luci-lib-nixio/docsrc/CHANGELOG.lua @@ -10,7 +10,7 @@ module "nixio.CHANGELOG" -- <li>Added support for x509 certificates in DER format.</li> -- <li>Added support for splice() in UnifiedIO.copyz().</li> -- <li>Added interface to inject chunks into UnifiedIO.linesource() buffer.</li> --- <li>Changed TLS behaviour to explicitely separate servers and clients.</li> +-- <li>Changed TLS behaviour to explicitly separate servers and clients.</li> -- <li>Fixed usage of signed datatype breaking Base64 decoding.</li> -- <li>Fixed namespace clashes for nixio.fs.</li> -- <li>Fixed splice() support for some exotic C libraries.</li> diff --git a/libs/luci-lib-nixio/docsrc/README.lua b/libs/luci-lib-nixio/docsrc/README.lua index 9860cf0919..d663b629ee 100644 --- a/libs/luci-lib-nixio/docsrc/README.lua +++ b/libs/luci-lib-nixio/docsrc/README.lua @@ -18,7 +18,7 @@ module "nixio.README" -- table <strong>nixio.const_sock</strong> for socket error codes. This might -- be important if you are dealing with Windows applications, on POSIX however -- const_sock is just an alias for const.</li> --- <li>With some exceptions - which are explicitely stated in the function +-- <li>With some exceptions - which are explicitly stated in the function -- documentation - all blocking functions are signal-protected and will not fail -- with EINTR.</li> -- <li>On POSIX the SIGPIPE signal will be set to ignore upon initialization. diff --git a/libs/luci-lib-nixio/docsrc/nixio.lua b/libs/luci-lib-nixio/docsrc/nixio.lua index 1a0d69a054..56a4afbb88 100644 --- a/libs/luci-lib-nixio/docsrc/nixio.lua +++ b/libs/luci-lib-nixio/docsrc/nixio.lua @@ -59,7 +59,7 @@ module "nixio" -- <li>aliases = Table of alias names</li> -- </ul> ---- Get all or a specifc proto entry. +--- Get all or a specific proto entry. -- @class function -- @name nixio.getproto -- @param proto protocol number or name to lookup (optional) diff --git a/libs/luci-lib-px5g/src/library/bignum.c b/libs/luci-lib-px5g/src/library/bignum.c index 8b7c12ff00..d2a8ff42e1 100644 --- a/libs/luci-lib-px5g/src/library/bignum.c +++ b/libs/luci-lib-px5g/src/library/bignum.c @@ -720,7 +720,7 @@ cleanup: } /* - * Helper for mpi substraction + * Helper for mpi subtraction */ static void mpi_sub_hlp( int n, t_int *s, t_int *d ) { @@ -741,7 +741,7 @@ static void mpi_sub_hlp( int n, t_int *s, t_int *d ) } /* - * Unsigned substraction: X = |A| - |B| (HAC 14.9) + * Unsigned subtraction: X = |A| - |B| (HAC 14.9) */ int mpi_sub_abs( mpi *X, mpi *A, mpi *B ) { @@ -809,7 +809,7 @@ cleanup: } /* - * Signed substraction: X = A - B + * Signed subtraction: X = A - B */ int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ) { @@ -856,7 +856,7 @@ int mpi_add_int( mpi *X, mpi *A, int b ) } /* - * Signed substraction: X = A - b + * Signed subtraction: X = A - b */ int mpi_sub_int( mpi *X, mpi *A, int b ) { diff --git a/libs/luci-lib-px5g/src/library/x509write.c b/libs/luci-lib-px5g/src/library/x509write.c index 173610c1a0..b9ebf35bae 100644 --- a/libs/luci-lib-px5g/src/library/x509write.c +++ b/libs/luci-lib-px5g/src/library/x509write.c @@ -19,7 +19,7 @@ * MA 02110-1301 USA */ /* - * The ITU-T X.509 standard defines a certificat format for PKI. + * The ITU-T X.509 standard defines a certificate format for PKI. * * http://www.ietf.org/rfc/rfc2459.txt * http://www.ietf.org/rfc/rfc3279.txt @@ -68,7 +68,7 @@ static int asn1_eval_octet(unsigned int digit) } /* - * write the asn.1 lenght form into p + * write the asn.1 length form into p */ static int asn1_add_len(unsigned int size, x509_node *node) { @@ -788,7 +788,7 @@ static int x509write_parse_names(x509_node *node, unsigned char *names) R_len = len; } - /* set tag poiner to begin */ + /* set tag pointer to begin */ tag_sp = tag; /* is at end? */ @@ -866,7 +866,7 @@ static int x509write_parse_names(x509_node *node, unsigned char *names) } /* - * Copy raw data from orginal ca to node + * Copy raw data from original ca to node */ static int x509write_copy_from_raw(x509_node *node, x509_buf *raw) { diff --git a/libs/luci-lib-px5g/src/polarssl/bignum.h b/libs/luci-lib-px5g/src/polarssl/bignum.h index c667303329..cf443ea922 100644 --- a/libs/luci-lib-px5g/src/polarssl/bignum.h +++ b/libs/luci-lib-px5g/src/polarssl/bignum.h @@ -272,7 +272,7 @@ int mpi_cmp_int( mpi *X, int z ); int mpi_add_abs( mpi *X, mpi *A, mpi *B ); /** - * \brief Unsigned substraction: X = |A| - |B| + * \brief Unsigned subtraction: X = |A| - |B| * * \return 0 if successful, * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A @@ -288,7 +288,7 @@ int mpi_sub_abs( mpi *X, mpi *A, mpi *B ); int mpi_add_mpi( mpi *X, mpi *A, mpi *B ); /** - * \brief Signed substraction: X = A - B + * \brief Signed subtraction: X = A - B * * \return 0 if successful, * 1 if memory allocation failed @@ -304,7 +304,7 @@ int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ); int mpi_add_int( mpi *X, mpi *A, int b ); /** - * \brief Signed substraction: X = A - b + * \brief Signed subtraction: X = A - b * * \return 0 if successful, * 1 if memory allocation failed diff --git a/libs/luci-lib-px5g/src/polarssl/x509.h b/libs/luci-lib-px5g/src/polarssl/x509.h index 908a1dbf51..6c9ef99a8a 100644 --- a/libs/luci-lib-px5g/src/polarssl/x509.h +++ b/libs/luci-lib-px5g/src/polarssl/x509.h @@ -375,7 +375,7 @@ int x509write_add_pubkey( x509_raw *chain, rsa_context *pubkey ); * the string parse. * * \param chain points to the raw certificate data - * \param names a string that can hold (separete with ";"): + * \param names a string that can hold (separate with ";"): * CN=CommonName * -- O=Organization * -- OU=OrgUnit @@ -402,7 +402,7 @@ int x509write_add_customize ( x509_raw *crt, * \brief Add x509 issuer field * * \param chain points to the raw certificate data -* \param issuer a string holding (separete with ";"): +* \param issuer a string holding (separate with ";"): * CN=CommonName * -- O=Organization * -- OU=OrgUnit @@ -419,7 +419,7 @@ int x509write_add_issuer( x509_raw *crt, unsigned char *issuer); * \brief Add x509 subject field * * \param chain points to the raw certificate data - * \param subject a string holding (separete with ";"): + * \param subject a string holding (separate with ";"): * CN=CommonName * -- O=Organization * -- OU=OrgUnit diff --git a/libs/rpcd-mod-rad2-enc/Makefile b/libs/rpcd-mod-rad2-enc/Makefile new file mode 100644 index 0000000000..4cffc01cd3 --- /dev/null +++ b/libs/rpcd-mod-rad2-enc/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (C) 2016-2017 Jo-Philipp Wich <jo@mein.io> +# +# Licensed under the Apache License, Version 2.0. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=rpcd-mod-rad2-enc +PKG_VERSION:=20190109 +PKG_MAINTAINER:=Daniel Dickinson <cshored@thecshore.com> + +PKG_LICENSE:=Apache-2.0 + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Build/Prepare + true +endef + +define Build/Compile + true +endef + +define Package/rpcd-mod-rad2-enc + SECTION:=libs + CATEGORY:=Libraries + TITLE:=Radicale 2.x Hashing RPC module + DEPENDS:=+rpcd +python3 +python3-passlib +endef + +define Package/rpcd-mod-rad2-enc/description + Python3 password hashing module for use Radicale 2.x LuCI app +endef + +define Package/rpcd-mod-rad2-enc/install + $(INSTALL_DIR) $(1)/usr/libexec/rpcd + $(INSTALL_BIN) ./files/rad2-enc $(1)/usr/libexec/rpcd +endef + +define Package/rpcd-mod-rad2-enc/postinst +#!/bin/sh +killall -HUP rpcd 2>/dev/null +exit 0 +endef + +$(eval $(call BuildPackage,rpcd-mod-rad2-enc)) diff --git a/libs/rpcd-mod-rad2-enc/files/rad2-enc b/libs/rpcd-mod-rad2-enc/files/rad2-enc new file mode 100755 index 0000000000..43bc49325c --- /dev/null +++ b/libs/rpcd-mod-rad2-enc/files/rad2-enc @@ -0,0 +1,50 @@ +#!/usr/bin/python3 + +import base64 +import sys +import json +from passlib import hash + +def main(): + + if len(sys.argv) < 2: + return -1 + + if sys.argv[1] == 'list': + print('{ "encrypt": { "type": "str", "plainpass": "str" } }\n') + return 0 + + if sys.argv[1] == 'call': + if len(sys.argv) < 3: + return -1 + + if sys.argv[2] != 'encrypt': + return -1 + + encpass = "" + try: + jsonin = json.loads(sys.stdin.readline()) + enctype = jsonin['type'].strip() + plainpass = jsonin['plainpass'] + + if enctype == 'ssha': + encpass = hash.ldap_salted_sha1.hash(plainpass) + elif enctype == 'sha1': + encpass = hash.ldap_sha1.hash(plainpass) + elif enctype == 'plain': + encpass = plainpass + elif enctype == 'md5': + encpass = hash.apr_md5_crypt.hash(plainpass) + elif enctype == 'bcrypt': + encpass = hash.bcrypt.hash(plainpass) + elif enctype == 'crypt': + encpass = hash.des_crypt.hash(plainpass) + + except: + encpass = "" + + print(json.dumps({ "encrypted_password": encpass})) + + return 0 + +main() |