# # patch "ChangeLog" # from [62f84027102e0ef51d71f5d62d5c58ae6e2eafa8] # to [338cb2bb88062aa7175096cd1a54936444d1a71f] # # patch "lua.cc" # from [2c76b85ac161a63912f30eab352abd8220b7b32c] # to [75f11ea114ded43701adba2c0e768c2731797f37] # # patch "monotone.texi" # from [303b2ddca2046e2e602515b2b72927f6a4dee8bb] # to [410d7f0020b615d72dbd8e454066e2090298f428] # # patch "std_hooks.lua" # from [d9534c87d99f1e4ac6159f1e4c6bf63eee72dd81] # to [5c6dc327e70325e6ab59b0da59b38cfb0a23a06d] # ======================================================================== --- ChangeLog 62f84027102e0ef51d71f5d62d5c58ae6e2eafa8 +++ ChangeLog 338cb2bb88062aa7175096cd1a54936444d1a71f @@ -1,3 +1,9 @@ +2005-10-25 Timothy Brownawell + + * lua.cc: make the globish matcher available to lua + * std_hooks.lua: new (better) format for read-permissions + * monotone.texi: update documentation + 2005-10-23 Timothy Brownawell * std_hooks.lua: new default get_netsync_*_permitted hooks, which ======================================================================== --- lua.cc 2c76b85ac161a63912f30eab352abd8220b7b32c +++ lua.cc 75f11ea114ded43701adba2c0e768c2731797f37 @@ -35,6 +35,7 @@ #include "platform.hh" #include "transforms.hh" #include "paths.hh" +#include "globish.hh" // defined in {std,test}_hooks.lua, converted #include "test_hooks.h" @@ -627,6 +628,35 @@ } static int + monotone_globish_match_for_lua(lua_State *L) + { + const char *re = lua_tostring(L, -2); + const char *str = lua_tostring(L, -1); + + bool result = false; + try { + string r(re); + string n; + string s(str); + result = globish_matcher(r, n)(s); + } catch (informative_failure & e) { + lua_pushstring(L, e.what.c_str()); + lua_error(L); + return 0; + } catch (boost::bad_pattern & e) { + lua_pushstring(L, e.what()); + lua_error(L); + return 0; + } catch (...) { + lua_pushstring(L, "Unknown error."); + lua_error(L); + return 0; + } + lua_pushboolean(L, result); + return 1; + } + + static int monotone_gettext_for_lua(lua_State *L) { const char *msgid = lua_tostring(L, -1); @@ -690,6 +720,16 @@ lua_pushcfunction(st, monotone_regex_search_for_lua); lua_settable(st, -3); + // add globish functions: + lua_newtable(st); + lua_pushstring(st, "globish"); + lua_pushvalue(st, -2); + lua_settable(st, LUA_GLOBALSINDEX); + + lua_pushstring(st, "match"); + lua_pushcfunction(st, monotone_globish_match_for_lua); + lua_settable(st, -3); + lua_pop(st, 1); } ======================================================================== --- monotone.texi 303b2ddca2046e2e602515b2b72927f6a4dee8bb +++ monotone.texi 410d7f0020b615d72dbd8e454066e2090298f428 @@ -5901,14 +5901,12 @@ the configuration directory. This file looks like @smallexample @group -[net.example.project.security*] -[net.example.project.private*] -! --all-- -joe@@example.net -jim@@example.net -[net.example.public*] -[net.example.project*] ---all-- +pattern "net.example.project.\{private,security\}*" +allow "joe@@example.net" +allow "jim@@example.net" + +pattern "net.example.\{public,project\}*" +allow "*" @end group @end smallexample This example allows everyone access to branches @code{net.example.project} and @@ -5916,17 +5914,20 @@ @code{net.example.security} and @code{net.example.private}, which are only readable by Joe and Jim. -The file is divided into sections of one or more lines in square brackets -followed by one or more lines not in square brackets. A line in square brackets -is a wildcard expression, which is matched against the @var{branch}. If one -matches, then the other lines in that section are compared against address@hidden A line @code{keyname} allows @code{keyname} read access, and a -line @code{! keyname} denies access. The special value @code{--all--} allows -read access to everyone (including anonymous), and @code{! --all--} means that -only keys allowed by this section have access. Without @code{! --all--}, if a -key is neither allowed nor denied permission in a section, the hook will keep -looking for matching sections in the rest of the file. +The file is divided into stanzas of one @code{pattern} line followed by any +number of @code{allow} and @code{deny} lines, and possibly a @code{continue} +line. Lines which do not consist of one of these words followed by an argument +in quotes will be ignored. A stanza is processed if the argument to address@hidden is a glob that matches @var{branch}. Any keys which match an address@hidden line are given access, and any keys which match a @code{deny} line +are denied access. If there is a @code{continue "true"} line, then if the key +is not granted or denied access in this stanza the next matching stanza will be +processed. If there is not a @code{continue "true"} line, then any key which +has not been given access will be denied access even if it doesn't match any address@hidden lines. Thus, deny lines are redundant unless there is also a address@hidden "true"} line. + If a client connects anonymously, this hook will be called with a @var{identity} of @code{nil}. @@ -5944,7 +5945,7 @@ files; otherwise @code{false}. The default definition of this hook reads a file @file{write-permissions} in the configuration directory which contains a list of keys, one per line, which are allowed write access. The special value address@hidden means to allow access to anyone whose public key we already have. address@hidden means to allow access to anyone whose public key we already have. If a client connects anonymously, it will be unconditionally denied write access; this hook will @emph{not} be called with a @var{identity} ======================================================================== --- std_hooks.lua d9534c87d99f1e4ac6159f1e4c6bf63eee72dd81 +++ std_hooks.lua 5c6dc327e70325e6ab59b0da59b38cfb0a23a06d @@ -781,52 +781,49 @@ os.remove (new_file); end -function wildcard_match(glob, str) - local pat = string.gsub(glob, "([%^%$%(%)%%%.%*%+%-%?])", "%%%1") - pat = string.gsub(pat, "%%%*", ".*") - pat = string.gsub(pat, "%%%?", ".") - pat = string.gsub(pat, "%[!", "%[%^") - return string.find(str, pat) +function globish_match(glob, str) + local pcallstatus, result = pcall(function() if (globish.match(glob, str)) then return true else return false end end) + if pcallstatus == true then + -- no error + return result + else + -- globish.match had a problem + return nil + end end +-- can't handle args with quotes in them, or lines with multiple args +function read_basicio_line(file) + local _, a, b + while _ == nil do + local line = file:read() + if line == nil then return nil end + _, _, a, b = string.find(line, "%s*([^%s]*)%s*\"([^\"]*)\"") + end + return a, b +end + function get_netsync_read_permitted(branch, ident) local permfile = io.open(get_confdir() .. "/read-permissions", "r") if (permfile == nil) then return false end - local fallthrough = true - local first = true - local line = permfile:read() - while line ~= nil and (first or fallthrough) do - -- find the appropriate section - local gotbr - while (line ~= nil and not gotbr) do - local foo, _, pat = string.find(line, "^%[(.*)%]$") - if foo then - gotbr = wildcard_match(pat, branch) - end - line = permfile:read() + local matches = false + local cont = false + while true do + local name, param = read_basicio_line(permfile) + if name == nil then return false end + if name == "pattern" then + if matches and not cont then return false end + matches = globish_match(param, branch) end - -- several [glob] lines immediately following eachother - -- share a list of allowed keys - while (line ~= nil and string.find(line, "^%[.*%]$")) do - line = permfile:read() - end - -- no matching entries - if not gotbr then return false end - -- check that section only - while (line ~= nil and not string.find(line, "^%[.*%]$")) do - local _, _, ln = string.find(line, "%s*([^%s]*)%s*") - local _, _, notln = string.find(line, "%s*!%s+([^%s]*)%s*") - if ln == "--all--" then return true end - if notln == "--all--" then fallthrough = false end - if ident ~= nil then - if ln == ident then return true end - if notln == ident then return false end + if matches then + if name == "continue" then + if param ~= "false" then cont = true end end - line = permfile:read() + if name == "allow" and param == "*" then return true end + if name == "allow" and globish_match(param, ident) then return true end + if name == "deny" and globish_match(param, ident) then return false end end - first = false end - io.close(permfile) return false end @@ -838,8 +835,8 @@ local line = permfile:read() while (line ~= nil) do local _, _, ln = string.find(line, "%s*([^%s]*)%s*") - if ln == "--all--" then return true end - if ln == ident then return true end + if ln == "*" then return true end + if globish_match(ln, ident) then return true end line = permfile:read() end io.close(permfile)