From fff5e48266b957e945236589ea0ea6393a6a33ff Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 28 Jul 2014 15:04:48 +0200 Subject: [PATCH 1/9] /index/match/ Signed-off-by: Steven Armstrong --- cdist/conf/type/__block/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote index 973e9922..c4788040 100755 --- a/cdist/conf/type/__block/gencode-remote +++ b/cdist/conf/type/__block/gencode-remote @@ -48,11 +48,11 @@ if [ -f "$file" ]; then fi awk -v prefix="^$prefix\\\$" -v suffix="^$suffix\\\$" ' { - if (index(\$0,prefix)) { + if (match(\$0,prefix)) { triggered=1 } if (triggered) { - if (index(\$0,suffix)) { + if (match(\$0,suffix)) { triggered=0 } } else { From 3dbe375837d69ff4d14e4f853326c487482aadec Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 28 Jul 2014 15:05:45 +0200 Subject: [PATCH 2/9] no need to double escape a trailing $; $ by itself is not special in any way Signed-off-by: Steven Armstrong --- cdist/conf/type/__block/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote index c4788040..2e2147e5 100755 --- a/cdist/conf/type/__block/gencode-remote +++ b/cdist/conf/type/__block/gencode-remote @@ -46,7 +46,7 @@ tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) if [ -f "$file" ]; then cp -p "$file" "\$tmpfile" fi -awk -v prefix="^$prefix\\\$" -v suffix="^$suffix\\\$" ' +awk -v prefix="^$prefix\$" -v suffix="^$suffix\$" ' { if (match(\$0,prefix)) { triggered=1 From ffd2935cc438e8e9ef7b7953f3d2201b2b2c7e5d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 25 Sep 2014 16:16:15 +0200 Subject: [PATCH 3/9] complete rewrite - add support for authorized_keys options see sshd(8) - add support for explicit comment after key - do not allow a key to exist more then once in an authorized_keys file - remove all conflicting keys Signed-off-by: Steven Armstrong --- .../__ssh_authorized_keys/explorer/entries | 32 ++++++++++++++++ .../explorer/{passwd => file} | 12 ++++-- .../type/__ssh_authorized_keys/explorer/group | 3 +- .../conf/type/__ssh_authorized_keys/man.text | 38 ++++++++++++++----- .../conf/type/__ssh_authorized_keys/manifest | 34 +++++++---------- .../__ssh_authorized_keys/parameter/optional | 4 +- 6 files changed, 88 insertions(+), 35 deletions(-) create mode 100755 cdist/conf/type/__ssh_authorized_keys/explorer/entries rename cdist/conf/type/__ssh_authorized_keys/explorer/{passwd => file} (68%) diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/entries b/cdist/conf/type/__ssh_authorized_keys/explorer/entries new file mode 100755 index 00000000..04e25880 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/entries @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# Find and sort any entries in the authorized_keys file that we care about + +file="$($__type_explorer/file)" + +( + while read key; do + # extract the keytype and base64 encoded key ignoring any options and comment + type_and_key="$(echo "$key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" + # emit any entries that match the type and key + grep ".*$type_and_key[ \n]" "$file" + done < "$__object/parameter/key" +) | sort diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/passwd b/cdist/conf/type/__ssh_authorized_keys/explorer/file similarity index 68% rename from cdist/conf/type/__ssh_authorized_keys/explorer/passwd rename to cdist/conf/type/__ssh_authorized_keys/explorer/file index e6352ee0..5a02721a 100755 --- a/cdist/conf/type/__ssh_authorized_keys/explorer/passwd +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/file @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -18,6 +18,10 @@ # along with cdist. If not, see . # -owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" - -getent passwd "$owner" || true +if [ -f "$__object/parameter/file" ]; then + cat "$__object/parameter/file" +else + owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" + home=$(getent passwd "$owner" | cut -d':' -f 6) + echo "$home/.ssh/authorized_keys" +fi diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/group b/cdist/conf/type/__ssh_authorized_keys/explorer/group index cdea6fe7..72a4e314 100755 --- a/cdist/conf/type/__ssh_authorized_keys/explorer/group +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/group @@ -18,5 +18,6 @@ # along with cdist. If not, see . # -gid="$("$__type_explorer/passwd" | cut -d':' -f 4)" +owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" +gid="$(getent passwd "$owner" | cut -d':' -f 4)" getent group "$gid" || true diff --git a/cdist/conf/type/__ssh_authorized_keys/man.text b/cdist/conf/type/__ssh_authorized_keys/man.text index 2e4202a7..d5523a6e 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.text +++ b/cdist/conf/type/__ssh_authorized_keys/man.text @@ -12,13 +12,13 @@ DESCRIPTION ----------- Adds or removes ssh keys from a authorized_keys file. -This type uses the __ssh_dot_ssh type to the directory containing -the authorized_keys file. -You can disable this feature with the --noparent boolean parameter. +This type uses the __ssh_dot_ssh type to manage the directory containing +the authorized_keys file. You can disable this feature with the --noparent +boolean parameter. The existence, ownership and permissions of the authorized_keys file itself are also managed. This can be disabled with the --nofile boolean parameter. It is -then left to the user to ensure that the file exists and that ownership and +then left to the user to ensure that the file exists and that ownership and permissions work with ssh. @@ -31,15 +31,23 @@ key:: OPTIONAL PARAMETERS ------------------- +comment:: + explicit comment instead of the one which may be trailing the given key + +file:: + an alternative destination file, defaults to ~$owner/.ssh/authorized_keys + +option:: + an option to set for all created authorized_key entries. + Can be specified multiple times. + See sshd(8) for available options. + owner:: the user owning the authorized_keys file, defaults to object_id. state:: if the given keys should be 'present' or 'absent', defaults to 'present'. -file:: - an alternative destination file, defaults to ~$owner/.ssh/authorized_keys - BOOLEAN PARAMETERS ------------------ @@ -64,13 +72,24 @@ __ssh_authorized_keys root \ __ssh_authorized_keys user-name \ --key "ssh-rsa AXYZAAB3NzaC1yc2..." +# allow key to login as user-name with options and expicit comment +__ssh_authorized_keys user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ + --option no-agent-forwarding \ + --option 'from="*.example.com"' \ + --comment 'backup server' + # same as above, but with explicit owner and two keys +# note that the options are set for all given keys __ssh_authorized_keys some-fancy-id \ --owner user-name \ --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ - --key "ssh-rsa AZXYAAB3NzaC1yc2..." + --key "ssh-rsa AZXYAAB3NzaC1yc2..." \ + --option no-agent-forwarding \ + --option 'from="*.example.com"' \ + --comment 'backup server' -# same as above, but authorized_keys file in non standard location +# authorized_keys file in non standard location __ssh_authorized_keys some-fancy-id \ --file /etc/ssh/keys/user-name/authorized_keys \ --owner user-name \ @@ -89,6 +108,7 @@ __ssh_authorized_keys some-fancy-id \ SEE ALSO -------- - cdist-type(7) +- sshd(8) COPYING diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 5885ec77..0fcfed5b 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -21,16 +21,7 @@ owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" state="$(cat "$__object/parameter/state" 2>/dev/null)" -if [ -f "$__object/parameter/file" ]; then - file="$(cat "$__object/parameter/file")" -else - home="$(cut -d':' -f 6 "$__object/explorer/passwd")" - if [ -z "$home" ]; then - echo "Failed to get home directory from explorer." >&2 - exit 1 - fi - file="$home/.ssh/authorized_keys" -fi +file="$(cat "$__object/explorer/file")" if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; then group="$(cut -d':' -f 1 "$__object/explorer/group")" @@ -50,6 +41,7 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; --group "$group" \ --mode 0600 \ --state exists + export require="__file/$file" fi fi @@ -63,22 +55,24 @@ __block "$__object_name" \ --text - << DONE remove legacy block DONE +export require="__block/$__object_name" _cksum() { echo "$1" | cksum | cut -d' ' -f 1 } while read key; do - cksum_key="$(_cksum "$key")" - line_id="${owner}-${cksum_key}" - - set -- "$line_id" + type_and_key="$(echo "$key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" + object_id="$(_cksum "$file")-$(_cksum "$type_and_key")" + set -- "$object_id" set -- "$@" --file "$file" - set -- "$@" --regex ".*$key.*" - if [ "$state" = 'present' ]; then - set -- "$@" --line "$key" - fi + set -- "$@" --key "$key" set -- "$@" --state "$state" - # Ensure __line does not read stdin - require="__block/$__object_name" __line "$@" < /dev/null + if [ -f "$__object/parameter/option" ]; then + set -- "$@" --option "$(cat "$__object/parameter/option")" + fi + if [ -f "$__object/parameter/comment" ]; then + set -- "$@" --comment "$(cat "$__object/parameter/comment")" + fi + __ssh_authorized_key "$@" done < "$__object/parameter/key" diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/optional b/cdist/conf/type/__ssh_authorized_keys/parameter/optional index 989750b3..21f9bc29 100644 --- a/cdist/conf/type/__ssh_authorized_keys/parameter/optional +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/optional @@ -1,3 +1,5 @@ +comment +file +option owner state -file From 68586a0c3dd6c45568901dc48458f76de451322f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 25 Sep 2014 16:23:38 +0200 Subject: [PATCH 4/9] new type to manage a single ssh authorized_key entry Signed-off-by: Steven Armstrong --- .../type/__ssh_authorized_key/explorer/entry | 26 +++++++ cdist/conf/type/__ssh_authorized_key/man.text | 67 +++++++++++++++++ cdist/conf/type/__ssh_authorized_key/manifest | 75 +++++++++++++++++++ .../parameter/default/state | 1 + .../__ssh_authorized_key/parameter/optional | 2 + .../parameter/optional_multiple | 1 + .../__ssh_authorized_key/parameter/required | 2 + 7 files changed, 174 insertions(+) create mode 100755 cdist/conf/type/__ssh_authorized_key/explorer/entry create mode 100644 cdist/conf/type/__ssh_authorized_key/man.text create mode 100755 cdist/conf/type/__ssh_authorized_key/manifest create mode 100644 cdist/conf/type/__ssh_authorized_key/parameter/default/state create mode 100644 cdist/conf/type/__ssh_authorized_key/parameter/optional create mode 100644 cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple create mode 100644 cdist/conf/type/__ssh_authorized_key/parameter/required diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry new file mode 100755 index 00000000..78031ab5 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# extract the keytype and base64 encoded key ignoring any options and comment +type_and_key="$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" +file="$(cat $__object/parameter/file)" + +# get any entries that match the type and key +grep ".*$type_and_key[ \n]" "$file" || true diff --git a/cdist/conf/type/__ssh_authorized_key/man.text b/cdist/conf/type/__ssh_authorized_key/man.text new file mode 100644 index 00000000..b519222c --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/man.text @@ -0,0 +1,67 @@ +cdist-type__ssh_authorized_key(7) +================================= +Steven Armstrong + + +NAME +---- +cdist-type__ssh_authorized_key - manage a single ssh authorized key entry + + +DESCRIPTION +----------- +Manage a single authorized key entry in an authorized_key file. +This type was created to be used by the __ssh_authorized_keys type. + + +REQUIRED PARAMETERS +------------------- +file:: + the authorized_keys file to which the given key should be added + +key:: + a string containing the ssh keytype, base 64 encoded key and optional + trailing comment which shall be added to the given authorized_keys file. + + +OPTIONAL PARAMETERS +------------------- +comment:: + explicit comment instead of the one which may be trailing the given key + +option:: + an option to set for this authorized_key entry. + Can be specified multiple times. + See sshd(8) for available options. + +state:: + if the given keys should be 'present' or 'absent', defaults to 'present'. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__ssh_authorized_key some-id \ + --file "/home/user/.ssh/autorized_keys" \ + --key "$(cat ~/.ssh/id_rsa.pub)" + +__ssh_authorized_key some-id \ + --file "/home/user/.ssh/autorized_keys" \ + --key "$(cat ~/.ssh/id_rsa.pub)" \ + --option 'command="/path/to/script"' \ + --option 'environment="FOO=bar"' \ + --comment 'one to rule them all' +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist__ssh_authorized_keys(7) +- sshd(8) + +COPYING +------- +Copyright \(C) 2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/manifest new file mode 100755 index 00000000..eb7ae859 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/manifest @@ -0,0 +1,75 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +file="$(cat "$__object/parameter/file")" +state="$(cat "$__object/parameter/state")" +mkdir "$__object/files" + +_cksum() { + echo "$1" | cksum | cut -d' ' -f 1 +} + +_do_line() { + file="$1" + line="$2" + state="$3" + line_id="$(_cksum "$file")-$(_cksum "$line")" + + set -- "$line_id" + set -- "$@" --file "$file" + set -- "$@" --line "$line" + set -- "$@" --state "$state" + # Ensure __line does not read stdin + __line "$@" < /dev/null +} + +# Generate the entry as it should be +( + if [ -f "$__object/parameter/option" ]; then + options="$(cat "$__object/parameter/option" | tr '\n' ',')" + printf '%s ' "${options%*,}" + fi + if [ -f "$__object/parameter/comment" ]; then + # extract the keytype and base64 encoded key ignoring any options and comment + printf '%s ' "$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" + # override the comment with the one explicitly given + printf '%s' "$(cat "$__object/parameter/comment")" + else + printf '%s' "$(cat "$__object/parameter/key")" + fi +) > "$__object/files/should" + +# Check for existing and conflicting entries and remove them +if [ -s "$__object/explorer/entry" ]; then + # We have existing entries for this key. + # Check if any of them are in conflict to how the entry should be. + # Note that the file has to be sorted for comparison with `comm`. + sort "$__object/explorer/entry" > "$__object/files/is" + comm -13 "$__object/files/should" "$__object/files/is" | { + # Remove conflicting entries + while read entry; do + _do_line "$file" "$entry" absent + done + } +fi + +# Manage the actual entry as it should be +entry="$(cat "$__object/files/should")" +_do_line "$file" "$entry" "$state" diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/default/state b/cdist/conf/type/__ssh_authorized_key/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/optional b/cdist/conf/type/__ssh_authorized_key/parameter/optional new file mode 100644 index 00000000..89e8d966 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/parameter/optional @@ -0,0 +1,2 @@ +comment +state diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple b/cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple new file mode 100644 index 00000000..01925a15 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple @@ -0,0 +1 @@ +option diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/required b/cdist/conf/type/__ssh_authorized_key/parameter/required new file mode 100644 index 00000000..d51426c3 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_key/parameter/required @@ -0,0 +1,2 @@ +file +key From eed058426a1ec1fc4dce68af2cb1cd3775c2a272 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 25 Sep 2014 16:35:19 +0200 Subject: [PATCH 5/9] fix that stupid stdin is truncated bug again Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_keys/manifest | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 0fcfed5b..6a536e1b 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -74,5 +74,6 @@ while read key; do if [ -f "$__object/parameter/comment" ]; then set -- "$@" --comment "$(cat "$__object/parameter/comment")" fi - __ssh_authorized_key "$@" + # Ensure __ssh_authorized_key does not read stdin + __ssh_authorized_key "$@" < /dev/null done < "$__object/parameter/key" From b17a1f0edbfc189c0eac47e94a08f763a2405834 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 27 Sep 2014 11:40:06 +0200 Subject: [PATCH 6/9] removing and adding keys must be atomic If we delegate this to multiple seprarate objects (e.g. using __line) and the config run is interrupted after applying only some of them we may leave the target in some random state. We may have even locked ourself out of the target. So remove and add keys ourself so either none are all changes are applied. Signed-off-by: Steven Armstrong --- .../{manifest => gencode-remote} | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) rename cdist/conf/type/__ssh_authorized_key/{manifest => gencode-remote} (63%) diff --git a/cdist/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/gencode-remote similarity index 63% rename from cdist/conf/type/__ssh_authorized_key/manifest rename to cdist/conf/type/__ssh_authorized_key/gencode-remote index eb7ae859..478826db 100755 --- a/cdist/conf/type/__ssh_authorized_key/manifest +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -18,31 +18,36 @@ # along with cdist. If not, see . # -file="$(cat "$__object/parameter/file")" -state="$(cat "$__object/parameter/state")" -mkdir "$__object/files" - -_cksum() { - echo "$1" | cksum | cut -d' ' -f 1 -} - -_do_line() { +remove_line() { file="$1" line="$2" - state="$3" - line_id="$(_cksum "$file")-$(_cksum "$line")" - - set -- "$line_id" - set -- "$@" --file "$file" - set -- "$@" --line "$line" - set -- "$@" --state "$state" - # Ensure __line does not read stdin - __line "$@" < /dev/null + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +if [ -f "$file" ]; then + cp -p "$file" "\$tmpfile" +fi +grep -v -F -x '$line' '$file' > \$tmpfile || true +mv -f "\$tmpfile" "$file" +DONE } +add_line() { + file="$1" + line="$2" + # escape single quotes + line_sanitised=$(echo "$line" | sed -e "s/'/'\"'\"'/g") + printf '%s' "printf '%s\n' '$line_sanitised' >> $file" +} + + +file="$(cat "$__object/parameter/file")" +mkdir "$__object/files" + # Generate the entry as it should be ( if [ -f "$__object/parameter/option" ]; then + # comma seperated list of options options="$(cat "$__object/parameter/option" | tr '\n' ',')" printf '%s ' "${options%*,}" fi @@ -56,20 +61,37 @@ _do_line() { fi ) > "$__object/files/should" -# Check for existing and conflicting entries and remove them +# Remove conflicting entries if any if [ -s "$__object/explorer/entry" ]; then - # We have existing entries for this key. - # Check if any of them are in conflict to how the entry should be. - # Note that the file has to be sorted for comparison with `comm`. + # Note that the files have to be sorted for comparison with `comm`. sort "$__object/explorer/entry" > "$__object/files/is" comm -13 "$__object/files/should" "$__object/files/is" | { - # Remove conflicting entries while read entry; do - _do_line "$file" "$entry" absent + remove_line "$file" "$entry" done } fi +# Determine the current state +state_should="$(cat "$__object/parameter/state")" +if grep -q -F -x "$entry" "$__object/explorer/entry"; then + state_is="present" +else + state_is="absent" +fi + # Manage the actual entry as it should be +if [ "$state_should" = "$state_is" ]; then + # Nothing to do + exit 0 +fi + entry="$(cat "$__object/files/should")" -_do_line "$file" "$entry" "$state" +case "$state_should" in + present) + add_line "$file" "$entry" + ;; + absent) + remove_line "$file" "$entry" + ;; +esac From 4125dfaab000ec1d5edd9b73c9caf3343e051d3d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 29 Sep 2014 10:46:00 +0200 Subject: [PATCH 7/9] them files should end in newline stupid Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_key/gencode-remote | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 478826db..7224f039 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -59,6 +59,7 @@ mkdir "$__object/files" else printf '%s' "$(cat "$__object/parameter/key")" fi + printf '\n' ) > "$__object/files/should" # Remove conflicting entries if any From 4c52b10f936e7aab0791ce37d51ed65a3f7332b2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 29 Sep 2014 10:57:27 +0200 Subject: [PATCH 8/9] maybe better define variable _before_ using it Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_key/gencode-remote | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 7224f039..8a5276b8 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -18,6 +18,8 @@ # along with cdist. If not, see . # +set -u + remove_line() { file="$1" line="$2" @@ -74,6 +76,7 @@ if [ -s "$__object/explorer/entry" ]; then fi # Determine the current state +entry="$(cat "$__object/files/should")" state_should="$(cat "$__object/parameter/state")" if grep -q -F -x "$entry" "$__object/explorer/entry"; then state_is="present" @@ -87,7 +90,6 @@ if [ "$state_should" = "$state_is" ]; then exit 0 fi -entry="$(cat "$__object/files/should")" case "$state_should" in present) add_line "$file" "$entry" From 41782cb10719d04b0650f2b51e86e3adef8fdea0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 29 Sep 2014 14:47:25 +0200 Subject: [PATCH 9/9] workaround special case where the desired key was already present more then once in target file Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_key/gencode-remote | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 8a5276b8..62c79ed2 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -78,9 +78,18 @@ fi # Determine the current state entry="$(cat "$__object/files/should")" state_should="$(cat "$__object/parameter/state")" -if grep -q -F -x "$entry" "$__object/explorer/entry"; then +num_existing_entries=$(grep -c -F -x "$entry" "$__object/explorer/entry") +if [ $num_existing_entries -eq 1 ]; then state_is="present" else + # Posix grep does not define the -m option, so we can not remove a single + # occurence of a string from a file in the `remove_line` function. Instead + # _all_ occurences are removed. + # By using `comm` to detect conflicting entries this could lead to the + # situation that the key we want to add is actually removed. + # To workaround this we must treat 0 or more then 1 existing entries to + # mean current state is 'absent'. By doing this, the key is readded + # again after cleaning up conflicting entries. state_is="absent" fi