forked from ungleich-public/cdist
		
	Merge branch 'fix/type/__postgres_role/implement-alter' into 'master'
__postgres_role: implement modification of roles See merge request ungleich-public/cdist!973
This commit is contained in:
		
				commit
				
					
						e854db096e
					
				
			
		
					 2 changed files with 226 additions and 54 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| #!/bin/sh | #!/bin/sh -e | ||||||
| # | # | ||||||
| # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | ||||||
|  | # 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) | ||||||
| # | # | ||||||
| # This file is part of cdist. | # This file is part of cdist. | ||||||
| # | # | ||||||
|  | @ -18,25 +19,133 @@ | ||||||
| # along with cdist. If not, see <http://www.gnu.org/licenses/>. | # along with cdist. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| case "$("${__explorer}/os")" | case $("${__explorer:?}/os") | ||||||
| in | in | ||||||
|     netbsd) | 	(netbsd) | ||||||
| 		postgres_user='pgsql' | 		postgres_user='pgsql' | ||||||
| 		;; | 		;; | ||||||
|     openbsd) | 	(openbsd) | ||||||
| 		postgres_user='_postgresql' | 		postgres_user='_postgresql' | ||||||
| 		;; | 		;; | ||||||
|     *) | 	(*) | ||||||
| 		postgres_user='postgres' | 		postgres_user='postgres' | ||||||
| 		;; | 		;; | ||||||
| esac | esac | ||||||
| 
 | 
 | ||||||
|  | rolename=${__object_id:?} | ||||||
| 
 | 
 | ||||||
| name="$__object_id" |  | ||||||
| 
 | 
 | ||||||
| if test -n "$(su - "$postgres_user" -c "psql postgres -twAc \"SELECT 1 FROM pg_roles WHERE rolname='$name'\"")" | psql_query() { | ||||||
|  | 	su -l "${postgres_user}" -c "$( | ||||||
|  | 		printf "psql -q -F '\034' -R '\036' -wAc '%s'" \ | ||||||
|  | 		"$(printf %s "$*" | sed "s/'/'\\\\''/g")" | ||||||
|  | 	)" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | password_check_login() ( | ||||||
|  | 	PGPASSWORD=$(cat "${__object:?}/parameter/password"; printf .) | ||||||
|  | 	PGPASSWORD=${PGPASSWORD%?.} | ||||||
|  | 	export PGPASSWORD | ||||||
|  | 	psql -q -w -h localhost -U "${rolename}" template1 -c '\q' >/dev/null 2>&1 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | role_properties=$( | ||||||
|  | 	psql_query "SELECT * FROM pg_roles WHERE rolname = '${rolename}'" \ | ||||||
|  | 	| awk ' | ||||||
|  | 	  BEGIN { RS = "\036"; FS = "\034" } | ||||||
|  | 	  /^\([0-9]+ rows?\)/ { exit } | ||||||
|  | 	  NR == 1 { for (i = 1; i <= NF; i++) cols[i] = $i; next } | ||||||
|  | 	  NR == 2 { for (i = 1; i <= NF; i++) printf "%s=%s\n", cols[i], $i } | ||||||
|  | 	  ' | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | if test -n "${role_properties}" | ||||||
| then | then | ||||||
|     echo 'present' | 	# Check if the user's properties match the parameters | ||||||
| else | 	for prop in login createdb createrole superuser | ||||||
|     echo 'absent' | 	do | ||||||
|  | 		bool_should=$(test -f "${__object:?}/parameter/${prop}" && echo 't' || echo 'f') | ||||||
|  | 		bool_is=$( | ||||||
|  | 			printf '%s\n' "${role_properties}" | | ||||||
|  | 			awk -F '=' -v key="${prop}" ' | ||||||
|  | 			BEGIN { | ||||||
|  | 				if (key == "login") | ||||||
|  | 					key = "canlogin" | ||||||
|  | 				else if (key == "superuser") | ||||||
|  | 					key = "super" | ||||||
|  | 				key = "rol" key | ||||||
|  | 			} | ||||||
|  | 			$1 == key { | ||||||
|  | 				sub(/^[^=]*=/, "") | ||||||
|  | 				print | ||||||
|  | 			} | ||||||
|  | 			' | ||||||
|  | 		) | ||||||
|  | 
 | ||||||
|  | 		test "${bool_is}" = "${bool_should}" || { | ||||||
|  | 			state='different properties' | ||||||
|  | 		} | ||||||
|  | 	done | ||||||
|  | 
 | ||||||
|  | 	# Check password | ||||||
|  | 	passwd_stored=$( | ||||||
|  | 		psql_query "SELECT rolpassword FROM pg_authid WHERE rolname = '${rolename}'" \ | ||||||
|  | 		| awk 'BEGIN { RS = "\036" } NR == 2' | ||||||
|  | 		printf . | ||||||
|  | 	) | ||||||
|  | 	passwd_stored=${passwd_stored%?.} | ||||||
|  | 
 | ||||||
|  | 	if test -f "${__object:?}/parameter/password" | ||||||
|  | 	then | ||||||
|  | 		passwd_should=$(cat "${__object:?}/parameter/password"; printf .) | ||||||
| 	fi | 	fi | ||||||
|  | 	passwd_should=${passwd_should%?.} | ||||||
|  | 
 | ||||||
|  | 	if test -z "${passwd_stored}" | ||||||
|  | 	then | ||||||
|  | 		test -z "${passwd_should}" || state="${state:-different} password" | ||||||
|  | 	elif expr "${passwd_stored}" : 'SCRAM-SHA-256\$.*$' >/dev/null | ||||||
|  | 	then | ||||||
|  | 		# SCRAM-SHA-256 "encrypted" password | ||||||
|  | 		# NOTE: There is currently no easy way to check SCRAM passwords without | ||||||
|  | 		#       logging in | ||||||
|  | 		password_check_login || state="${state:-different} password" | ||||||
|  | 	elif expr "${passwd_stored}" : 'md5[0-9a-f]\{32\}$' >/dev/null | ||||||
|  | 	then | ||||||
|  | 		# MD5 "encrypted" password | ||||||
|  | 		if command -v md5sum >/dev/null 2>&1 | ||||||
|  | 		then | ||||||
|  | 			should_md5=$( | ||||||
|  | 				printf '%s%s' "${passwd_should}" "${rolename}" \ | ||||||
|  | 				| md5sum - | sed -e 's/[^0-9a-f]*$//') | ||||||
|  | 		elif command -v gmd5sum >/dev/null 2>&1 | ||||||
|  | 		then | ||||||
|  | 			should_md5=$( | ||||||
|  | 				printf '%s%s' "${passwd_should}" "${rolename}" \ | ||||||
|  | 				| gmd5sum - | sed -e 's/[^0-9a-f]*$//') | ||||||
|  | 		elif command -v openssl >/dev/null 2>&1 | ||||||
|  | 		then | ||||||
|  | 			should_md5=$( | ||||||
|  | 				printf '%s%s' "${passwd_should}" "${rolename}" \ | ||||||
|  | 				| openssl dgst -md5 | sed 's/^.* //') | ||||||
|  | 		fi | ||||||
|  | 
 | ||||||
|  | 		if test -n "${should_md5}" | ||||||
|  | 		then | ||||||
|  | 			test "${passwd_stored}" = "md5${should_md5}" \ | ||||||
|  | 			|| state="${state:-different} password" | ||||||
|  | 		else | ||||||
|  | 			password_check_login || state="${state:-different} password" | ||||||
|  | 		fi | ||||||
|  | 	else | ||||||
|  | 		# unencrypted password (unsupported since PostgreSQL 10) | ||||||
|  | 		test "${passwd_stored}" = "${passwd_should}" \ | ||||||
|  | 		|| state="${state:-different} password" | ||||||
|  | 	fi | ||||||
|  | 
 | ||||||
|  | 	test -n "${state}" || state='present' | ||||||
|  | else | ||||||
|  | 	state='absent' | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | echo "${state}" | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #!/bin/sh -e | #!/bin/sh -e | ||||||
| # | # | ||||||
| # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | ||||||
|  | # 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) | ||||||
| # | # | ||||||
| # This file is part of cdist. | # This file is part of cdist. | ||||||
| # | # | ||||||
|  | @ -18,48 +19,110 @@ | ||||||
| # along with cdist. If not, see <http://www.gnu.org/licenses/>. | # along with cdist. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| case "$(cat "${__global}/explorer/os")" | quote() { | ||||||
|  | 	if test $# -gt 0 | ||||||
|  | 	then | ||||||
|  | 		printf '%s' "$*" | ||||||
|  | 	else | ||||||
|  | 		cat - | ||||||
|  | 	fi | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | case $(cat "${__global:?}/explorer/os") | ||||||
| in | in | ||||||
|     netbsd) | 	(netbsd) | ||||||
| 		postgres_user='pgsql' | 		postgres_user='pgsql' | ||||||
| 		;; | 		;; | ||||||
|     openbsd) | 	(openbsd) | ||||||
| 		postgres_user='_postgresql' | 		postgres_user='_postgresql' | ||||||
| 		;; | 		;; | ||||||
|     *) | 	(*) | ||||||
| 		postgres_user='postgres' | 		postgres_user='postgres' | ||||||
| 		;; | 		;; | ||||||
| esac | esac | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| name="$__object_id" | rolename=${__object_id:?} | ||||||
| state_is="$(cat "$__object/explorer/state")" | state_is=$(cat "${__object:?}/explorer/state") | ||||||
| state_should="$(cat "$__object/parameter/state")" | state_should=$(cat "${__object:?}/parameter/state") | ||||||
| 
 | 
 | ||||||
| [ "$state_is" = "$state_should" ] && exit 0 | if test "${state_is}" = "${state_should}" | ||||||
|  | then | ||||||
|  | 	exit 0 | ||||||
|  | fi | ||||||
| 
 | 
 | ||||||
| case "$state_should" in | psql_query() { | ||||||
|     present) | 	printf 'su -l %s -c %s\n' \ | ||||||
|         if [ -f "$__object/parameter/password" ]; then | 		"$(quote "${postgres_user}")" \ | ||||||
|             password="$(cat "$__object/parameter/password")" | 		"$(quote "psql postgres -q -w -c $(quote "$1")")" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | psql_set_password() { | ||||||
|  | 	# NOTE: Always make sure that the password does not end up in psql_history! | ||||||
|  | 	# NOTE: Never set an empty string as the password, because they can be | ||||||
|  | 	#       interpreted differently by different tooling. | ||||||
|  | 	if test -s "${__object:?}/parameter/password" | ||||||
|  | 	then | ||||||
|  | 		cat <<-EOF | ||||||
|  | 		exec 3< "\${__object:?}/parameter/password" | ||||||
|  | 		su -l '${postgres_user}' -c 'psql -q -w postgres' <<'SQL' | ||||||
|  | 		\set HISTFILE /dev/null | ||||||
|  | 		\set pw \`cat <&3\` | ||||||
|  | 		ALTER ROLE "${rolename}" WITH PASSWORD :'pw'; | ||||||
|  | 		SQL | ||||||
|  | 		exec 3<&- | ||||||
|  | 		EOF | ||||||
|  | 	else | ||||||
|  | 		psql_query "ALTER ROLE \"${rolename}\" WITH PASSWORD NULL;" | ||||||
| 	fi | 	fi | ||||||
|         booleans="" | } | ||||||
|         for boolean in login createdb createrole superuser; do | 
 | ||||||
|             if [ ! -f "$__object/parameter/$boolean" ]; then | role_properties_should() { | ||||||
|                 boolean="no${boolean}" | 	_props= | ||||||
|             fi | 	for _prop in login createdb createrole superuser | ||||||
|             upper=$(echo $boolean | tr '[:lower:]' '[:upper:]') | 	do | ||||||
|             booleans="$booleans $upper" | 		_props="${_props}${_props:+ }$( | ||||||
|  | 			if test -f "${__object:?}/parameter/${_prop}" | ||||||
|  | 			then | ||||||
|  | 				echo "${_prop}" | ||||||
|  | 			else | ||||||
|  | 				echo "no${_prop}" | ||||||
|  | 			fi \ | ||||||
|  | 			| tr '[:lower:]' '[:upper:]')" | ||||||
| 	done | 	done | ||||||
|  | 	printf '%s\n' "${_props}" | ||||||
|  | 	unset _prop _props | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|         [ -n "$password" ] && password="PASSWORD '$password'" | case ${state_should} | ||||||
|         cat << EOF | in | ||||||
| su - '$postgres_user' -c "psql postgres -wc \"CREATE ROLE \\\\\"$name\\\\\" WITH $password $booleans;\"" | 	(present) | ||||||
| EOF | 		case ${state_is} | ||||||
|  | 		in | ||||||
|  | 			(absent) | ||||||
|  | 				psql_query "CREATE ROLE \"${rolename}\" WITH $(role_properties_should);" | ||||||
|  | 				psql_set_password | ||||||
| 				;; | 				;; | ||||||
|     absent) | 			(different*) | ||||||
|         cat << EOF | 				if expr "${state_is}" : 'different.*properties' >/dev/null | ||||||
| su - '$postgres_user' -c "dropuser \"$name\"" | 				then | ||||||
| EOF | 					psql_query "ALTER ROLE \"${rolename}\" WITH $(role_properties_should);" | ||||||
|  | 				fi | ||||||
|  | 
 | ||||||
|  | 				if expr "${state_is}" : 'different.*password' >/dev/null | ||||||
|  | 				then | ||||||
|  | 					psql_set_password | ||||||
|  | 				fi | ||||||
|  | 				;; | ||||||
|  | 			(*) | ||||||
|  | 				printf 'Invalid state reported by state explorer: %s\n' "${state_is}" >&2 | ||||||
|  | 				exit 1 | ||||||
|  | 				;; | ||||||
|  | 		esac | ||||||
|  | 		;; | ||||||
|  | 	(absent) | ||||||
|  | 		printf 'su -l %s -c %s\n' \ | ||||||
|  | 			"$(quote "${postgres_user}")" \ | ||||||
|  | 			"$(quote "dropuser $(quote "${rolename}")")" | ||||||
| 		;; | 		;; | ||||||
| esac | esac | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue