From 80e91b3ebb3ed7ecb842f5327013b5fc4d70c649 Mon Sep 17 00:00:00 2001 From: Mike McRill Date: Thu, 1 Feb 2024 08:00:42 -0600 Subject: [PATCH] Fix line and add group/user libraries --- go/initdir/init_test.go | 2 +- go/initdir/lib/etcha/group.libsonnet | 17 +++++++++ go/initdir/lib/etcha/line.libsonnet | 5 +-- go/initdir/lib/etcha/password.libsonnet | 15 -------- go/initdir/lib/etcha/user.libsonnet | 26 ++++++++++++++ go/initdir/patterns/lib_test.jsonnet | 43 ++++++++++++++++++++--- hugo/content/docs/references/libraries.md | 11 +++--- 7 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 go/initdir/lib/etcha/group.libsonnet delete mode 100644 go/initdir/lib/etcha/password.libsonnet create mode 100644 go/initdir/lib/etcha/user.libsonnet diff --git a/go/initdir/init_test.go b/go/initdir/init_test.go index 6859fb9..c1ff264 100644 --- a/go/initdir/init_test.go +++ b/go/initdir/init_test.go @@ -32,7 +32,7 @@ func TestInit(t *testing.T) { p, err := pattern.ParsePatternFromPath(ctx, c, "", "init/patterns/lib_test.jsonnet") assert.HasErr(t, err, nil) - assert.Equal(t, len(p.Run), 24) + assert.Equal(t, len(p.Run), 36) assert.Equal(t, len(p.Imports.Files), len(d)+2) // 2=lib_test.jsonnet, native.libsonnet os.Remove("etcha") diff --git a/go/initdir/lib/etcha/group.libsonnet b/go/initdir/lib/etcha/group.libsonnet new file mode 100644 index 0000000..e9e4769 --- /dev/null +++ b/go/initdir/lib/etcha/group.libsonnet @@ -0,0 +1,17 @@ +// Manage a local group. Must specify id and name. Can optionally specify members, paths to group and gshadow, and enable removal. + +local line = import './line.libsonnet'; + +function(id, members='', name, pathGroup='/etc/group', pathGshadow='/etc/gshadow', remove=false) + local vars = { + id: id, + members: members, + name: name, + }; + + local replaceRemove = if remove then '""'; + + [ + line(match='"(?m)^%s:.*"' % name, path=pathGroup, replaceChange='"%(name)s:x:%(id)s:%(members)s"' % vars, replaceRemove=replaceRemove), + line(match='"(?m)^%s:.*"' % name, path=pathGshadow, replaceChange='"%(name)s:|::%(members)s"' % vars, replaceRemove=replaceRemove), + ] diff --git a/go/initdir/lib/etcha/line.libsonnet b/go/initdir/lib/etcha/line.libsonnet index a9e1684..19c3b32 100644 --- a/go/initdir/lib/etcha/line.libsonnet +++ b/go/initdir/lib/etcha/line.libsonnet @@ -1,6 +1,6 @@ // Manage a line at path. Can set the contents, owner and group, ignore content changes, and set the mode. Will append the line to the end of the file during a change if nothing matches. -function(match, path, replaceChange, replaceRemove='""') +function(match, path, replaceChange, replaceRemove=null) local vars = { match: match, path: path, @@ -9,8 +9,9 @@ function(match, path, replaceChange, replaceRemove='""') }; { - id: 'line %s' % path, + id: 'line %s %s' % [path, replaceChange], check: 'etcha line check %(path)s %(match)s %(replaceChange)s' % vars, change: 'etcha line change %(path)s %(match)s %(replaceChange)s' % vars, + } + if replaceRemove == null then {} else { remove: 'etcha line change %(path)s %(match)s %(replaceRemove)s' % vars, } diff --git a/go/initdir/lib/etcha/password.libsonnet b/go/initdir/lib/etcha/password.libsonnet deleted file mode 100644 index 3614486..0000000 --- a/go/initdir/lib/etcha/password.libsonnet +++ /dev/null @@ -1,15 +0,0 @@ -// Manage a password for a user. - -function(hash, path='/etc/shadow', user='root') - { - change: ||| - # shellcheck disable=SC2016 - sed -i 's|^\(%s:\)[^:]*\(:.*\)$|\1%s\2|' %s - ||| % [user, hash, path], - check: 'grep "%s:%s:" %s' % [user, hash, path], - id: '%s password hash' % user, - remove: ||| - # shellcheck disable=SC2016 - sed -i 's|^\(%s:\)[^:]*\(:.*\)$|\1*\2|' %s - ||| % [user, path], - } diff --git a/go/initdir/lib/etcha/user.libsonnet b/go/initdir/lib/etcha/user.libsonnet new file mode 100644 index 0000000..48be3f1 --- /dev/null +++ b/go/initdir/lib/etcha/user.libsonnet @@ -0,0 +1,26 @@ +// Manage a local user. Must specify id and name. Can optionally specify members, paths to group and gshadow, and disable removal. + +local line = import './line.libsonnet'; + +function(comment, gid, hash='*', home='/bin', id, name, pathPasswd='/etc/passwd', pathShadow='/etc/shadow', remove=false, shell='/usr/sbin/nologin') + local vars = { + comment: comment, + gid: gid, + hash: hash, + home: home, + id: id, + name: name, + shell: shell, + }; + + local replaceRemove = if remove then '""' else null; + + [ + { + id: '%s password age' % name, + check: '(grep %s: /etc/shadow || echo "::$(($(date +%%s)/60/60/24))") | cut -d: -f3' % name, + envPrefix: 'age', + }, + line(match='"(?m)^%s:.*"' % name, path=pathPasswd, replaceChange='"%(name)s:x:%(id)s:%(gid)s:%(comment)s:%(home)s:%(shell)s"' % vars, replaceRemove=replaceRemove), + line(match='"(?m)^%s:.*"' % name, path=pathShadow, replaceChange='"%(name)s:%(hash)s:${age_CHECK_OUT}:0:99999:7:::"' % vars, replaceRemove=replaceRemove), + ] diff --git a/go/initdir/patterns/lib_test.jsonnet b/go/initdir/patterns/lib_test.jsonnet index 623734c..ef6f203 100644 --- a/go/initdir/patterns/lib_test.jsonnet +++ b/go/initdir/patterns/lib_test.jsonnet @@ -4,11 +4,12 @@ local copy = import '../lib/etcha/copy.libsonnet'; local dir = import '../lib/etcha/dir.libsonnet'; local etchaInstall = import '../lib/etcha/etchaInstall.libsonnet'; local file = import '../lib/etcha/file.libsonnet'; +local group = import '../lib/etcha/group.libsonnet'; local line = import '../lib/etcha/line.libsonnet'; local mount = import '../lib/etcha/mount.libsonnet'; -local password = import '../lib/etcha/password.libsonnet'; local symlink = import '../lib/etcha/symlink.libsonnet'; local systemdUnit = import '../lib/etcha/systemdUnit.libsonnet'; +local user = import '../lib/etcha/user.libsonnet'; { run: [ @@ -30,13 +31,47 @@ local systemdUnit = import '../lib/etcha/systemdUnit.libsonnet'; dir(group='daemon', mode='0700', owner='daemon', path='testdata/test'), etchaInstall(cacheDir='testdata/test', dst='testdata/etcha'), etchaInstall(dst='testdata/etcha1'), - file(contents='root:*:19352:0:99999:7:::', group='daemon', owner='daemon', ignoreContents=true, path='testdata/shadow'), - line(match='19352', path='testdata/shadow', replaceChange='19352!', replaceRemove='19352'), + file(contents=||| + root:x:0:0:root:/root:/bin/bash + daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin + bin:x:2:2:bin:/bin:/usr/sbin/nologin + sys:x:3:3:sys:/dev:/usr/sbin/nologin + sync:x:4:65534:sync:/bin:/bin/sync + games:x:2010:60:samba:/home/games:/bin/false + |||, group='daemon', owner='daemon', ignoreContents=true, path='testdata/passwd'), + file(contents=||| + root:*:18919:0:99999:7::: + daemon:*:18907:0:99999:7::: + bin:*:18907:0:99999:7::: + sys:*:18907:0:99999:7::: + sync:*:18907:0:99999:7::: + games:*:18907:0:99999:7::: + |||, group='daemon', owner='daemon', ignoreContents=true, path='testdata/shadow'), + line(match='18919', path='testdata/shadow', replaceChange='18920', replaceRemove='18919'), + user(comment='syncer', gid='444', hash='123', home='/sbin', id='5', name='sync', pathPasswd='testdata/passwd', pathShadow='testdata/shadow', remove=false, shell='/bin/bash'), + user(comment='syncer', gid='444', hash='123', home='/sbin', id='5', name='syncer', pathPasswd='testdata/passwd', pathShadow='testdata/shadow', remove=false, shell='/bin/bash'), + file(contents=||| + root:x:0: + daemon:x:1: + bin:x:2: + sys:x:3: + adm:x:4: + tty:x:5: + |||, ignoreContents=true, path='testdata/group'), + file(contents=||| + root:*:: + daemon:*:: + bin:*:: + sys:*:: + adm:*:: + tty:*:: + |||, ignoreContents=true, path='testdata/gshadow'), + group(id='4', members='user1,user2', name='adm', pathGroup='testdata/group', pathGshadow='testdata/gshadow'), + group(id='1000', members='user3,user4', name='admins', pathGroup='testdata/group', pathGshadow='testdata/gshadow', remove=true), file(contents='hello', path='testdata/world'), file(path='testdata/touch'), dir(path='testdata/src'), mount(args='-o bind', dst='testdata/dst', src='testdata/src'), - password(hash='notahash', path='testdata/shadow'), symlink(src='testdata/shadow', dst='testdata/shadowsym'), systemdUnit(contents=||| [Unit] diff --git a/hugo/content/docs/references/libraries.md b/hugo/content/docs/references/libraries.md index 0e87bc8..c60d2bd 100644 --- a/hugo/content/docs/references/libraries.md +++ b/hugo/content/docs/references/libraries.md @@ -35,21 +35,20 @@ See [Writing Patterns]({{< ref "/docs/guides/writing-patterns" >}}) for more inf ### `file` {{% etcha-library "file" %}} +### `group` +{{% etcha-library "group" %}} + ### `line` {{% etcha-library "line" %}} ### `mount` {{% etcha-library "mount" %}} -### `password` -{{% etcha-library "password" %}} - ### `symlink` {{% etcha-library "symlink" %}} ### `systemdUnit` {{% etcha-library "systemdUnit" %}} - - - +### `user` +{{% etcha-library "user" %}}