From 6fbca72d680bb7ce7bccb41c86becf1762b042c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 10 May 2014 01:10:59 +0300 Subject: testing/aaudit: rewrite client in lua, use json in configs also use json to talk between client and server. and make the client program handle all command line flags. --- testing/aaudit/APKBUILD | 76 +++++---- testing/aaudit/aaudit | 79 +++++++-- testing/aaudit/aaudit-common.lua | 31 ++++ testing/aaudit/aaudit-repo-create | 51 ------ testing/aaudit/aaudit-repo-update | 25 --- testing/aaudit/aaudit-server.conf | 29 ---- testing/aaudit/aaudit-server.json | 20 +++ testing/aaudit/aaudit-server.lua | 331 ++++++++++++++++++++++++++++++++++++++ testing/aaudit/aaudit-shell | 19 +-- testing/aaudit/aaudit-update-keys | 18 +++ testing/aaudit/aaudit.json | 5 + testing/aaudit/aaudit.lua | 267 ------------------------------ 12 files changed, 528 insertions(+), 423 deletions(-) mode change 100644 => 100755 testing/aaudit/aaudit create mode 100644 testing/aaudit/aaudit-common.lua delete mode 100755 testing/aaudit/aaudit-repo-create delete mode 100755 testing/aaudit/aaudit-repo-update delete mode 100644 testing/aaudit/aaudit-server.conf create mode 100644 testing/aaudit/aaudit-server.json create mode 100644 testing/aaudit/aaudit-server.lua create mode 100755 testing/aaudit/aaudit-update-keys create mode 100644 testing/aaudit/aaudit.json delete mode 100644 testing/aaudit/aaudit.lua (limited to 'testing/aaudit') diff --git a/testing/aaudit/APKBUILD b/testing/aaudit/APKBUILD index f471ed92fa..5dcb358aca 100644 --- a/testing/aaudit/APKBUILD +++ b/testing/aaudit/APKBUILD @@ -1,57 +1,71 @@ # Contributor: Timo Teräs # Maintainer: Timo Teräs pkgname=aaudit -pkgver=0.3 +pkgver=0.4 pkgrel=0 pkgdesc="Alpine Auditor" url="http://alpinelinux.org" arch="noarch" license="GPL" -depends="" +depends="lua5.2 lua5.2-posix lua5.2-cjson" makedepends="" install="" subpackages="$pkgname-server" replaces="" -client_bin="aaudit" -server_bin="aaudit-repo-create aaudit-repo-update aaudit-shell" -server_lua="aaudit.lua" -source="$client_bin $server_lua $server_bin aaudit-server.conf" +source="aaudit-common.lua + aaudit-server.lua + aaudit + aaudit-shell + aaudit-update-keys + aaudit.json + aaudit-server.json + " +_luaver="5.2" build() { return 0 } package() { - mkdir -p "$pkgdir"/usr/bin - cp $client_bin "$pkgdir"/usr/bin + mkdir -p "$pkgdir"/etc/aaudit \ + "$pkgdir"/usr/bin \ + "$pkgdir"/usr/share/lua/$_luaver/aaudit + cp aaudit.json "$pkgdir"/etc/aaudit + cp aaudit-common.lua "$pkgdir"/usr/share/lua/$_luaver/aaudit/common.lua + cp aaudit "$pkgdir"/usr/bin } server() { - depends="lua5.2 lua5.2-posix git" + depends="aaudit git lua5.2 lua5.2-posix lua5.2-cjson" mkdir -p "$subpkgdir"/etc/aaudit \ "$subpkgdir"/usr/libexec/aaudit \ - "$subpkgdir"/usr/share/lua/5.2/ - cp aaudit-server.conf "$subpkgdir"/etc/aaudit - cp $server_lua "$subpkgdir"/usr/share/lua/5.2/ - cp $server_bin "$subpkgdir"/usr/libexec/aaudit + "$subpkgdir"/usr/bin \ + "$subpkgdir"/usr/share/lua/$_luaver/aaudit + cp aaudit-server.json "$subpkgdir"/etc/aaudit + cp aaudit-server.lua "$subpkgdir"/usr/share/lua/$_luaver/aaudit/server.lua + cp aaudit-update-keys "$subpkgdir"/usr/bin + cp aaudit-shell "$subpkgdir"/usr/libexec/aaudit } -md5sums="e8ea430114aab3f07704060605670e0b aaudit -c7733c44b464e6e8efe73826d075af17 aaudit.lua -b11fe0d8285a00a135f8ac9af0206449 aaudit-repo-create -b900f83afedc4fb1dae2f74c9380fb72 aaudit-repo-update -0958044c64d1b5c475939687a5620a41 aaudit-shell -274e2126de7f30170ad6d6acc1bb9ef1 aaudit-server.conf" -sha256sums="093ded6192adc7ee81ec1e435bac4652355950c30c573cbd0d2f9ab1307f1ade aaudit -c4e64cd76a23a6e10f944f88904ec7bc511be90af0659526745086fb732530f7 aaudit.lua -f01ecd5b99cadbc591d8472f6010d34ad3136085aa35c93d7da56b29a251f6c1 aaudit-repo-create -2c108a129411373be55a4e4add7ca5c005e05f1ca48be813e9903f7ef84f1e7e aaudit-repo-update -8a24abf3ff360f74afbf408d38ad5336a17f59bf0ec9ff553cae4fe0a4bfc376 aaudit-shell -23e75c1c935d2cd516c489c0c6835178e864595daef45975da54897296aebcf6 aaudit-server.conf" -sha512sums="b52acc614c4437ed54f348daeb887aca965b62b4e45bbd1f95b731f5e03b360277476b513254e05306387cdea1f196a86b4d9cf5bbc76916707164b45364521d aaudit -9d64ba1904639aca31f34aa384cdfce7ddefd17959dfb08904811015343e36959904707ff667879e0fa5587f199ff4dac0213a42d484f983801914dc61ae2899 aaudit.lua -a8c875eb726e267d6fb56f41cb5c39c45e6f8af8a7a55059bcaff8a0fe8498dac2c90bb21c88e37c34658c574bf2afa8f6ef24e725f602ee1153ba04d9cc84d5 aaudit-repo-create -e59320cbc6bd7a07687a261399b7df4ef00e349240bee64539a9dfd925b05fb6c679f0f8efb42d1429a7c1d6b918d429a6acb0bc3d4d7f6ef059f9562b748abf aaudit-repo-update -492f342115dfe1b622601d11edeb2e5bc87512412645c9f242ce5fe870e6c6a5ee333aa8e3dcb7f9b7f72ebce8b8cb88d6446af39255485c0bd3786ab2c81982 aaudit-shell -b370c408c242cb4d4c349ca2208e69cdc44c750990c8aacb62e2d8b018cdb87e25c5955fe144352f0fd5c41ff0329ed1118fb3a977aa40e13ddb6b115bf4dd2a aaudit-server.conf" +md5sums="b81b0707b297a69dacbc1606324de029 aaudit-common.lua +4ad8c883f09133a1b9357f7ac156040c aaudit-server.lua +b24162b7fa31161eab71485b1077f8ea aaudit +07c54e8cb44f195456be7a18b15a0be1 aaudit-shell +feef077f56f40002ca11846512d347af aaudit-update-keys +e14ded329626ca1d6dd48e5bef0bc7e2 aaudit.json +dc9a54c08ea299ad268301266f3da989 aaudit-server.json" +sha256sums="ee1998e730356c2de0ff9d5e27d9e0277e3c1f051777146b7c5b820437edfd7f aaudit-common.lua +3a9384089b0cb73c151b67eaedd66a244b48c0c2a86f5fe0ccadda6e0cbe8863 aaudit-server.lua +198b92b5a0eb8e13c3fad87f3afffda1e749243c785e72b54db190413a513595 aaudit +a99ab6908d780f07b756f5d2416924250b61e88c92ea0aa91af88a05dfc9edff aaudit-shell +660dcf86f02a9d0e3ff47cb359e0291a0921d03215e368552a2878d2d691a9cc aaudit-update-keys +f61efebc04756c8bfb7cb955b7af5db6a3c5dabdd005f690db812c7e77567cf5 aaudit.json +878fa7c12ddd28d679703cdf7ab31f69473609d16da9604545f78132cc59d562 aaudit-server.json" +sha512sums="aaa378fd710d17cb3663954648e97dd5128406cc6f37e9834075046aed1912dcc9e448b6c96502350b8d3496e00b7803cae671a4be2c12c584a84dc0b6e843e9 aaudit-common.lua +fa74091c9f8f2614f68d828560734b92f16b592b40e9552464ef84dc54f2600f7df91e9ba6159c3a91d54f8d4160078ac022e585633a87edc0cbc6e280a29be9 aaudit-server.lua +b15515979003382527842cf3fd0c150fb1ff96009518e7cd71c42ab0cf091cee000384d2b8b71c6cc8c4c93ee64cb70bef726d98b3e2b87fff9db7afbc83dc57 aaudit +974a4e733a61c07719ae75bc1ffc39f01d5adf7bc7f813aa358201bd18711eafeaa42705d9b8d4a869cdb27687091c8998b7eafd1d10a778a429d0efa787bda0 aaudit-shell +aec728a9a1e4c92baeb94a9d95e1785ea166652a157571fe2e848e71c1246635ecb99512e92435e1314c620b1fa8e4f37400350bed78bd375db4a63828c500f0 aaudit-update-keys +e769f0f77fe54ba1ab35efc80cc6426e34a2ee1d053ac9e7cc5aa316cfcef0c9658d2f0e2c47f7ae282bb9cc07107065fcc13034b2f9125c182378b7c73b7d99 aaudit.json +dcc099fe53603a09de225a888242ce329cdb51af3cd0a88dea23cb56d794eb2a442dcdf93b3db18158f8745d5d33de5c82d106f99b1c616fd4936512dfae75d8 aaudit-server.json" diff --git a/testing/aaudit/aaudit b/testing/aaudit/aaudit old mode 100644 new mode 100755 index 489fd30164..a1e835272f --- a/testing/aaudit/aaudit +++ b/testing/aaudit/aaudit @@ -1,9 +1,70 @@ -#!/bin/sh -CONF="/etc/aaudit/aaudit.conf" -[ -r "$CONF" ] && . "$CONF" -AAUDIT_USER=${AAUDIT_USER:-aaudit} -if [ -z "$AAUDIT_SERVER" ]; then - echo "Initialize $CONF with AAUDIT_SERVER= first!" - exit 0 -fi -exec ssh $AAUDIT_USER@$AAUDIT_SERVER "$@" +#!/usr/bin/lua5.2 + +local posix = require 'posix' +local json = require 'cjson' +local aac = require 'aaudit.common' + +local function usage() + print([[ +Usage: aaudit [create|commit] [OPTIONS...] + +Valid options for create: + -s SERV Use server SERV + -d DESC Description for repository (default: hostname) + -t ADDR Specify ADDR as target device (default: local source IP) + -m MSG Specify message for the initial commit + -g GRP Add in group GRP + +Valid options for commit: + -m MSG Specify message for the commit + -r RT Related to ticket RT + -c RT Closes ticket RT +]]) + os.exit(1) +end + +local conf = aac.readconfig() or {} +local req = {} + +for ret, optval in posix.getopt(arg, 's:d:t:m:g:r:c:') do + if ret == 's' then + conf.server = optval + elseif ret == 'd' then + conf.description = optval + elseif ret == 't' then + conf.target_address = optval + elseif ret == 'm' then + req.message = optval + elseif ret == 'g' then + req.groups = req.groups or {} + table.insert(req.groups, optval) + elseif ret == 'r' then + req.ticket = optval + elseif ret == 'c' then + req.ticket = optval + req.ticket_action = "close" + else + usage() + end +end + +if conf.server == nil then + print("Error: No server configured.") + usage() +end + +req.command = arg[1] +if arg[1] == "create" then + req.description = conf.description or aac.readfile("/etc/hostname"):gsub("\n","") + req.ssh_host_key = aac.readfile("/etc/ssh/ssh_host_ecdsa_key.pub") + or aac.readfile("/etc/ssh/ssh_host_dsa_key.pub") + or aac.readfile("/etc/ssh/ssh_host_rsa_key.pub") + aac.writeconfig(conf) +elseif arg[1] == "commit" then +else + usage() +end + +local F = io.popen(("ssh -T %s@%s "):format(conf.user or "aaudit", conf.server), "w") +F:write(json.encode(req)) +F:close() diff --git a/testing/aaudit/aaudit-common.lua b/testing/aaudit/aaudit-common.lua new file mode 100644 index 0000000000..d7b1bc4837 --- /dev/null +++ b/testing/aaudit/aaudit-common.lua @@ -0,0 +1,31 @@ +local M = {} + +local posix = require 'posix' +local json = require 'cjson' + +M.config = "/etc/aaudit/aaudit.json" + +function M.readfile(fn) + local F = io.open(fn, "r") + if F == nil then return nil end + local ret = F:read("*all") + F:close() + return ret +end + +function M.readconfig(fn) + fn = fn or M.config + local success, res = pcall(json.decode, M.readfile(fn)) + if not success then io.stderr:write(("Error reading %s: %s\n"):format(fn, res)) end + return res +end + +function M.writefile(content, fn) + assert(io.open(fn, "w")):write(content):close() +end + +function M.writeconfig(config, fn) + M.writefile(json.encode(config), fn or M.config) +end + +return M diff --git a/testing/aaudit/aaudit-repo-create b/testing/aaudit/aaudit-repo-create deleted file mode 100755 index 7b3ce91220..0000000000 --- a/testing/aaudit/aaudit-repo-create +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/lua5.2 - -local posix = require 'posix' -local aaudit = require 'aaudit' - -local function usage() - print("usage: aaudit-repo-create [-a ADDRESS] -d DESCRIPTION [-i COMMIT_IDENTITY] [-m COMMIT_MESSAGE] [-g GROUPS]") - os.exit(1) -end - -local C = { initial=true } -local groups = {} -local address, description - -for ret, optval in posix.getopt(arg, 'a:d:g:i:m:') do - if ret == 'a' then - address = optval - elseif ret == 'd' then - description = optval - elseif ret == 'g' then - groups['"'..optval..'"'] = true - elseif ret == 'i' then - C.identity = optval - elseif ret == 'm' then - C.message = optval - else - usage() - end -end - -if not address or not description then usage() end - --- For now default to use address as the repository name -local repo, repohome = address, aaudit.repohome(address) - --- Create repository + write config -os.execute(([[ -mkdir -p %s; cd %s -git init --quiet --bare -]]):format(repohome, repohome)) - -aaudit.write_file(("%s/aaudit.conf"):format(repohome), ([[ -address = "%s"; -description = "%s"; -groups = { %s }; -]]):format(address, description, table.concat(groups, ', '))) - -aaudit.write_file(("%s/description"):format(repohome), ("%s (%s)"):format(description, address)) - --- Initial import of configuration -aaudit.import_commit(repohome, C) diff --git a/testing/aaudit/aaudit-repo-update b/testing/aaudit/aaudit-repo-update deleted file mode 100755 index 3aa4cc5854..0000000000 --- a/testing/aaudit/aaudit-repo-update +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/lua5.2 - -local posix = require 'posix' -local aaudit = require 'aaudit' - -local function usage() - print("usage: aaudit-repo-update [-i COMMIT_IDENTITY] [-m COMMIT_MESSAGE]") - os.exit(1) -end - -local C = { } -local address -for ret, optval in posix.getopt(arg, 'a:i:m:') do - if ret == 'a' then - address = optval - elseif ret == 'i' then - C.identity = optval - elseif ret == 'm' then - C.message = optval - else - usage() - end -end - -aaudit.import_commit(aaudit.repohome(address), C) diff --git a/testing/aaudit/aaudit-server.conf b/testing/aaudit/aaudit-server.conf deleted file mode 100644 index 34ad9b2cec..0000000000 --- a/testing/aaudit/aaudit-server.conf +++ /dev/null @@ -1,29 +0,0 @@ --- smtp_server = ""; - -identities = { -}; - -groups = { - all = { - notify_email = { "engineers@alpine.local" }; - track_filemode = true; - - no_track = { - "*/.git/*", - "*.apk-new", - "*~", - "etc/unbound/root.hints", - "etc/chrony/chrony.drift", - "etc/ld.so.cache", - }; - no_notify = { - "etc/acf/password", - }; - no_diff = { - "etc/shadow*", - "*.crt", - "*.pem", - "*.pfx", - }; - }; -}; diff --git a/testing/aaudit/aaudit-server.json b/testing/aaudit/aaudit-server.json new file mode 100644 index 0000000000..b2edcef650 --- /dev/null +++ b/testing/aaudit/aaudit-server.json @@ -0,0 +1,20 @@ +{ + "smtp_server": "localhost", + "identities": { + "_default": "Alpine Auditor " + }, + "groups": { + "all": { + "notify_email": [ "Notify Group " ], + "track_filemode": true, + "no_track": [ + "*/.git/*", "*.apk-new", "*~", + "etc/unbound/root.hints", + "etc/chrony/chrony.drift", + "etc/ld.so.cache" + ], + "no_notify": [ "etc/acf/password" ], + "no_diff": [ "etc/shadow*", "*.crt","*.pem", "*.pfx" ] + } + } +} diff --git a/testing/aaudit/aaudit-server.lua b/testing/aaudit/aaudit-server.lua new file mode 100644 index 0000000000..56fed28c14 --- /dev/null +++ b/testing/aaudit/aaudit-server.lua @@ -0,0 +1,331 @@ +local M = {} + +local posix = require 'posix' +local json = require 'cjson' +local aac = require 'aaudit.common' + +local HOME = os.getenv("HOME") + +local function merge_bool(a, b) return a or b end +local function merge_array(a, b) if b then for i=1,#b do a[#a+1] = b[i] end end return a end + +local function match_file(fn, match_list) + if not match_list then return false end + local i, m + for i, pattern in ipairs(match_list) do + if posix.fnmatch(pattern, fn) then return true end + end + return false +end + +local function sortedpairs(t) + local i, keys, k = 0, {} + for k in pairs(t) do keys[#keys+1] = k end + table.sort(keys) + return function() + i = i + 1 + if keys[i] then return keys[i], t[keys[i]] end + end +end + +local function checksum_header(block) + local sum = 256 + for i = 1,148 do sum = sum + block:byte(i) end + for i = 157,500 do sum = sum + block:byte(i) end + return sum +end + +local function nullterm(s) return s:match("^[^%z]*") end +local function octal_to_number(str) return tonumber(nullterm(str), 8) end + +local function read_header_block(block) + local header = { + name = nullterm(block:sub(1,100)), + mode = octal_to_number(block:sub(101,108)), + uid = octal_to_number(block:sub(109,116)), + gid = octal_to_number(block:sub(117,124)), + size = octal_to_number(block:sub(125,136)), + mtime = octal_to_number(block:sub(137,148)), + chksum = octal_to_number(block:sub(149,156)), + typeflag = block:sub(157,157), + linkname = nullterm(block:sub(158,257)), + magic = block:sub(258,263), + version = block:sub(264,265), + uname = nullterm(block:sub(266,297)), + gname = nullterm(block:sub(298,329)), + devmajor = octal_to_number(block:sub(330,337)), + devminor = octal_to_number(block:sub(338,345)), + prefix = nullterm(block:sub(346,500)), + } + if header.magic ~= "ustar " and header.magic ~= "ustar\0" then + return false, "Invalid header magic "..header.magic + end + if header.version ~= "00" and header.version ~= " \0" then + return false, "Unknown version "..header.version + end + if not checksum_header(block) == header.chksum then + return false, "Failed header checksum" + end + return header +end + +local function import_tar(TAR, GIT, req, G) + local branch_ref = "refs/heads/import" + local from_ref = "refs/heads/master" + local blocksize = 512 + local zeroblock = string.rep("\0", blocksize) + local nextmark = 1 + local author_time = 0 + local all_files = {} + local long_name, long_link_name + local symlinkmode = tonumber('0120000', 8) + local rwmode = tonumber('0755', 8) + local romode = tonumber('0644', 8) + local wandmode = tonumber('0111', 8) + + while true do + local block = TAR:read(blocksize) + if not block then + return false, "Premature end of archive" + end + if block == zeroblock then break end + + local header, err = read_header_block(block) + if not header then return false, err end + + local file_data = TAR:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) + if header.typeflag == "L" then + long_name = nullterm(file_data) + elseif header.typeflag == "K" then + long_link_name = nullterm(file_data) + else + if long_name then + header.name = long_name + long_name = nil + end + if long_link_name then + header.linkname = long_link_name + long_link_name = nil + end + end + + if header.typeflag:match("^[0-46]$") and + not match_file(header.name, G.no_track) then + GIT:write('blob\n', 'mark :', nextmark, '\n') + if header.typeflag == "2" then + GIT:write('data ', tostring(#header.linkname), '\n', header.linkname, '\n') + header.mode = symlinkmode + else + GIT:write('data ', tostring(header.size), '\n', file_data, '\n') + end + local fn = header.prefix..header.name + all_files[fn] = { mark=nextmark, mode=header.mode, uname=header.uname, gname=header.gname } + nextmark = nextmark + 1 + if header.mtime > author_time then author_time = header.mtime end + end + end + if G.track_filemode then + GIT:write('blob\n', 'mark :', nextmark, '\n', + 'data <$") + if email then return {name=name, email=email, rfc822=("%s <%s>"):format(name, email) } end + return {name="", email=name, rfc822=("<%s>"):format(name)} +end + +local function send_email(body, req, S, R, G) + if not body then return end + if not G.notify_emails then return end + + local to_rfc822 = {} + local to_email = {} + for _,r in ipairs(G.notify_emails) do + local id = resolve_email(S.identities, r) + if not to_email[id.email] then + to_email[id.email] = true + table.insert(to_rfc822, id.rfc822) + table.insert(to_email, id.email) + end + end + to_rfc822 = table.concat(to_rfc822, ", ") + to_email = table.concat(to_email, " ") + + local EMAIL = io.popen(('/bin/busybox sendmail -f "%s" -S "%s" %s') + :format(req.author.email, S.smtp_server, to_email), "w") + EMAIL:write(([[ +From: %s +To: %s +Subject: apkovl changed - %s (%s) +Date: %s + +]]):format(req.author.rfc822, to_rfc822, R.description, R.address, os.date("%a, %d %b %Y %H:%M:%S"))) + + for _, l in ipairs(body) do EMAIL:write(l,'\n') end + EMAIL:close() + + return to_email +end + +local function load_repo_configs(repohome) + local S = aac.readconfig(("%s/aaudit-server.json"):format(HOME)) + local R = aac.readconfig(("%s/aaudit-repo.json"):format(repohome)) + -- merge global and per-repository group configs + local G = (S.groups or {}).all or {} + for _, name in pairs(R.groups or {}) do + local g = S.groups[name] or {} + G.notify_emails = merge_array(G.notify_emails, g.notify_emails) + G.track_filemode = merge_bool(G.track_filemode, g.track_filemode) + G.no_track = merge_array(G.no_track, g.no_track) + G.no_notify = merge_array(G.no_notify, g.no_notify) + G.no_diff = merge_array(G.no_diff, g.no_diff) + end + return S, R, G +end + +function M.repo_update(req) + local repodir = req.repositorydir + local S, R, G = load_repo_configs(repodir) + + req.author = resolve_email(S.identities, req.identity) + + local TAR = io.popen(("ssh root@%s 'lbu package -' | gunzip"):format(R.address), "r") + local GIT = io.popen(("git --git-dir='%s' fast-import --quiet"):format(repodir), "w") + local rc, err = import_tar(TAR, GIT, req, G) + GIT:close() + TAR:close() + if not rc then return rc, err end + + local has_changes, email_body = generate_diff(repodir, "import", G) + if has_changes then + os.execute(("git --git-dir='%s' branch --quiet --force master import;".. + "git --git-dir='%s' branch --quiet -D import") + :format(repodir, repodir)) + local to = nil + if not req.initial then + to = send_email(email_body, req, S, R, G) + end + if to then + return true, "Committed and notified: "..to + else + return true, "Commit successful" + end + end + + os.execute(("git --git-dir='%s' branch --quiet -D import;".. + "git --git-dir='%s' gc --quiet --prune=now") + :format(repodir, repodir)) + return true, "No changes detected" +end + +function M.repo_create(req) + -- Create repository + write config + local repodir = req.repositorydir + os.execute(("mkdir -p '%s'; git init --quiet --bare '%s'") + :format(repodir, repodir)) + aac.writefile( + ("%s (%s)"):format(req.description, req.target_address), + ("%s/description"):format(repodir)) + aac.writeconfig( + { address=req.target_address, + description=req.description, + groups=req.groups }, + ("%s/aaudit-repo.json"):format(repodir)) + + -- Inject ssh identity to known_hosts + if req.ssh_host_key then + local f = io.open(("%s/.ssh/known_hosts"):format(HOME), "a") + f:write(("%s %s\n"):format(req.target_address, req.ssh_host_key)) + f:close() + end +end + +function M.handle(req) + req.target_address = req.target_address or req.remote_ip + req.repositorydir = ("%s/%s.git"):format(HOME, req.target_address) + req.initial = false + if req.command == "create" then + if posix.access(req.repositorydir, "rwx") then + return false, "Repository exists already" + end + M.repo_create(req) + req.initial = true + req.command = "commit" + end + if req.command == "commit" then + if not posix.access(req.repositorydir, "rwx") then + return false, "No such repository" + end + return M.repo_update(req) + else + return false,"Invalid request command" + end +end + +return M diff --git a/testing/aaudit/aaudit-shell b/testing/aaudit/aaudit-shell index 73ebd2e7eb..e54ac3a977 100755 --- a/testing/aaudit/aaudit-shell +++ b/testing/aaudit/aaudit-shell @@ -1,14 +1,11 @@ -#!/bin/sh +#!/usr/bin/lua5.2 -local ip="${SSH_CLIENT/ */}" -local identity="$1" -[ -z "$ip" -o -z "$identity" ] && exit 1 +local json = require 'cjson' +local aas = require 'aaudit.server' -set -- $SSH_ORIGINAL_COMMAND -cmd="$1" -shift +local req = json.decode(io.read("*all")) +req.remote_ip = (os.getenv("SSH_CLIENT") or ""):match("[^ ]+") +req.identity = arg[1] -case "$cmd" in -create) /usr/libexec/aaudit/aaudit-repo-create -a "$ip" "$@" -i "$identity" ;; -commit) /usr/libexec/aaudit/aaudit-repo-update -a "$ip" "$@" -i "$identity" ;; -esac +local ok, msg = aas.handle(req) +print(json.encode{ok=ok,msg=msg}) diff --git a/testing/aaudit/aaudit-update-keys b/testing/aaudit/aaudit-update-keys new file mode 100755 index 0000000000..3521808cba --- /dev/null +++ b/testing/aaudit/aaudit-update-keys @@ -0,0 +1,18 @@ +#!/usr/bin/lua5.2 + +local posix = require 'posix' +local aac = require 'aaudit.common' + +local home = os.getenv("HOME") +local allkeys = {} +for _, keyfile in ipairs(posix.glob(("%s/keydir/*.pub"):format(home))) do + local identity = keyfile:match("keydir/(.*).pub$") + for sshkey in io.lines(keyfile) do + table.insert(allkeys, + ('command="/usr/libexec/aaudit/aaudit-shell %s"'.. + ',no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s\n') + :format(identity, sshkey)) + end +end + +aac.writefile(table.concat(allkeys), ("%s/.ssh/authorized_keys"):format(home)) diff --git a/testing/aaudit/aaudit.json b/testing/aaudit/aaudit.json new file mode 100644 index 0000000000..958d60fbc6 --- /dev/null +++ b/testing/aaudit/aaudit.json @@ -0,0 +1,5 @@ +{ + "user": "aaudit", + "server": "aaudit.alpine.local", + "rtqueue": "alpine.org" +} diff --git a/testing/aaudit/aaudit.lua b/testing/aaudit/aaudit.lua deleted file mode 100644 index 915c177e71..0000000000 --- a/testing/aaudit/aaudit.lua +++ /dev/null @@ -1,267 +0,0 @@ -local M = {} - -local posix = require 'posix' - -function M.repohome(repo) - return ("%s/%s.git"):format(os.getenv("HOME"), repo) -end - -function M.write_file(filename, content) - assert(io.open(filename, "w")):write(content):close() -end - -local function load_config(filename) - local F = assert(io.open(filename, "r")) - local cfg = "return {" .. F:read("*all").. "}" - F:close() - return loadstring(cfg, "config:"..filename)() -end - -local function merge_bool(a, b) return a or b end -local function merge_dict(a, b) for k, v in pairs(b) do a[k] = v end return a end -local function merge_array(a, b) for i=1,#b do a[#a+1] = b[i] end return a end - -local function load_repo_configs(repohome) - local G = load_config(("%s/aaudit.conf"):format(os.getenv("HOME"))) - local R = load_config(("%s/aaudit.conf"):format(repohome)) - -- merge global and per-repository group configs - local RG = (G.groups or {}).all - for g in pairs(R.groups or {}) do - RG.notify_emails = merge_dict(RG.notify_emails, g.notify_emails) - RG.track_filemode = merge_bool(RG.track_filemode, g.track_filemode) - RG.no_track = merge_array(RG.no_track, g.no_track) - RG.no_notify = merge_array(RG.no_notify, g.no_notify) - RG.no_diff = merge_array(RG.no_diff, g.no_diff) - end - return G, R, RG -end - -local function match_file(fn, match_list) - if not match_list then return false end - local i, m - for i, pattern in ipairs(match_list) do - if posix.fnmatch(pattern, fn) then return true end - end - return false -end - -local function sortedpairs(t) - local i, keys, k = 0, {} - for k in pairs(t) do keys[#keys+1] = k end - table.sort(keys) - return function() - i = i + 1 - if keys[i] then return keys[i], t[keys[i]] end - end -end - -local function checksum_header(block) - local sum = 256 - for i = 1,148 do sum = sum + block:byte(i) end - for i = 157,500 do sum = sum + block:byte(i) end - return sum -end - -local function nullterm(s) return s:match("^[^%z]*") end -local function octal_to_number(str) return tonumber(nullterm(str), 8) end - -local function read_header_block(block) - local header = { - name = nullterm(block:sub(1,100)), - mode = octal_to_number(block:sub(101,108)), - uid = octal_to_number(block:sub(109,116)), - gid = octal_to_number(block:sub(117,124)), - size = octal_to_number(block:sub(125,136)), - mtime = octal_to_number(block:sub(137,148)), - chksum = octal_to_number(block:sub(149,156)), - typeflag = block:sub(157,157), - linkname = nullterm(block:sub(158,257)), - magic = block:sub(258,263), - version = block:sub(264,265), - uname = nullterm(block:sub(266,297)), - gname = nullterm(block:sub(298,329)), - devmajor = octal_to_number(block:sub(330,337)), - devminor = octal_to_number(block:sub(338,345)), - prefix = nullterm(block:sub(346,500)), - } - if header.magic ~= "ustar " and header.magic ~= "ustar\0" then - return false, "Invalid header magic "..header.magic - end - if header.version ~= "00" and header.version ~= " \0" then - return false, "Unknown version "..header.version - end - if not checksum_header(block) == header.chksum then - return false, "Failed header checksum" - end - return header -end - -local function import_tar(TAR, GIT, CI, RG) - local branch_ref = "refs/heads/import" - local from_ref = "refs/heads/master" - local blocksize = 512 - local zeroblock = string.rep("\0", blocksize) - local nextmark = 1 - local author_time = 0 - local all_files = {} - local long_name, long_link_name - local symlinkmode = tonumber('0120000', 8) - local rwmode = tonumber('0755', 8) - local romode = tonumber('0644', 8) - local wandmode = tonumber('0111', 8) - - while true do - local block = TAR:read(blocksize) - if not block then - return false, "Premature end of archive" - end - if block == zeroblock then break end - - local header, err = read_header_block(block) - if not header then return false, err end - - local file_data = TAR:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) - if header.typeflag == "L" then - long_name = nullterm(file_data) - elseif header.typeflag == "K" then - long_link_name = nullterm(file_data) - else - if long_name then - header.name = long_name - long_name = nil - end - if long_link_name then - header.linkname = long_link_name - long_link_name = nil - end - end - - if header.typeflag:match("^[0-46]$") and - not match_file(header.name, RG.no_track) then - GIT:write('blob\n', 'mark :', nextmark, '\n') - if header.typeflag == "2" then - GIT:write('data ', tostring(#header.linkname), '\n', header.linkname, '\n') - header.mode = symlinkmode - else - GIT:write('data ', tostring(header.size), '\n', file_data, '\n') - end - local fn = header.prefix..header.name - all_files[fn] = { mark=nextmark, mode=header.mode, uname=header.uname, gname=header.gname } - nextmark = nextmark + 1 - if header.mtime > author_time then author_time = header.mtime end - end - end - if RG.track_filemode then - GIT:write('blob\n', 'mark :', nextmark, '\n', - 'data < %d +0000 -committer %s <%s> %d +0000 -data < -To: %s -Subject: apkovl changed - %s (%s) -Date: %s - -]]):format( CI.identity_name, CI.identity_email, - table.concat(RG.notify_emails, ", "), - R.description, R.address, - os.date("%a, %d %b %Y %H:%M:%S"))) - - for _, l in ipairs(body) do EMAIL:write(l,'\n') end - EMAIL:close() -end - -function M.import_commit(repohome, CI) - local G, R, RG = load_repo_configs(repohome) - - CI.identity_name, CI.identity_email = table.unpack(G.identities[CI.identity]) - CI.identity_name = CI.identity_name or "Alpine Auditor" - CI.identity_email = CI.identity_email or "auditor@alpine.local" - - local TAR = io.popen(("ssh root@%s 'lbu package -' | gunzip"):format(R.address), "r") - local GIT = io.popen(("cd %s; git fast-import --quiet"):format(repohome), "w") - local rc, err = import_tar(TAR, GIT, CI, RG) - GIT:close() - TAR:close() - if not rc then return rc, err end - - local has_changes, email_body = generate_diff(repohome, "import", RG) - if has_changes then - if not CI.initial then send_email(CONF, email_body, CI, G, R, RG) end - os.execute(("cd %s; git branch --quiet --force master import; git branch --quiet -D import"):format(repohome)) - else - os.execute(("cd %s; git branch --quiet -D import; git gc --quiet --prune=now"):format(repohome)) - end - -end - -return M -- cgit v1.2.3