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) | ||||
| # 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) | ||||
| # | ||||
| # This file is part of cdist. | ||||
| # | ||||
|  | @ -18,25 +19,133 @@ | |||
| # along with cdist. If not, see <http://www.gnu.org/licenses/>. | ||||
| # | ||||
| 
 | ||||
| case "$("${__explorer}/os")" | ||||
| case $("${__explorer:?}/os") | ||||
| in | ||||
|     netbsd) | ||||
| 	(netbsd) | ||||
| 		postgres_user='pgsql' | ||||
| 		;; | ||||
|     openbsd) | ||||
| 	(openbsd) | ||||
| 		postgres_user='_postgresql' | ||||
| 		;; | ||||
|     *) | ||||
| 	(*) | ||||
| 		postgres_user='postgres' | ||||
| 		;; | ||||
| 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 | ||||
|     echo 'present' | ||||
| else | ||||
|     echo 'absent' | ||||
| 	# Check if the user's properties match the parameters | ||||
| 	for prop in login createdb createrole superuser | ||||
| 	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 | ||||
| 	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 | ||||
| # | ||||
| # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | ||||
| # 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) | ||||
| # | ||||
| # This file is part of cdist. | ||||
| # | ||||
|  | @ -18,48 +19,110 @@ | |||
| # 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 | ||||
|     netbsd) | ||||
| 	(netbsd) | ||||
| 		postgres_user='pgsql' | ||||
| 		;; | ||||
|     openbsd) | ||||
| 	(openbsd) | ||||
| 		postgres_user='_postgresql' | ||||
| 		;; | ||||
|     *) | ||||
| 	(*) | ||||
| 		postgres_user='postgres' | ||||
| 		;; | ||||
| esac | ||||
| 
 | ||||
| 
 | ||||
| name="$__object_id" | ||||
| state_is="$(cat "$__object/explorer/state")" | ||||
| state_should="$(cat "$__object/parameter/state")" | ||||
| rolename=${__object_id:?} | ||||
| state_is=$(cat "${__object:?}/explorer/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 | ||||
|     present) | ||||
|         if [ -f "$__object/parameter/password" ]; then | ||||
|             password="$(cat "$__object/parameter/password")" | ||||
| psql_query() { | ||||
| 	printf 'su -l %s -c %s\n' \ | ||||
| 		"$(quote "${postgres_user}")" \ | ||||
| 		"$(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 | ||||
|         booleans="" | ||||
|         for boolean in login createdb createrole superuser; do | ||||
|             if [ ! -f "$__object/parameter/$boolean" ]; then | ||||
|                 boolean="no${boolean}" | ||||
|             fi | ||||
|             upper=$(echo $boolean | tr '[:lower:]' '[:upper:]') | ||||
|             booleans="$booleans $upper" | ||||
| } | ||||
| 
 | ||||
| role_properties_should() { | ||||
| 	_props= | ||||
| 	for _prop in login createdb createrole superuser | ||||
| 	do | ||||
| 		_props="${_props}${_props:+ }$( | ||||
| 			if test -f "${__object:?}/parameter/${_prop}" | ||||
| 			then | ||||
| 				echo "${_prop}" | ||||
| 			else | ||||
| 				echo "no${_prop}" | ||||
| 			fi \ | ||||
| 			| tr '[:lower:]' '[:upper:]')" | ||||
| 	done | ||||
| 	printf '%s\n' "${_props}" | ||||
| 	unset _prop _props | ||||
| } | ||||
| 
 | ||||
|         [ -n "$password" ] && password="PASSWORD '$password'" | ||||
|         cat << EOF | ||||
| su - '$postgres_user' -c "psql postgres -wc \"CREATE ROLE \\\\\"$name\\\\\" WITH $password $booleans;\"" | ||||
| EOF | ||||
| case ${state_should} | ||||
| in | ||||
| 	(present) | ||||
| 		case ${state_is} | ||||
| 		in | ||||
| 			(absent) | ||||
| 				psql_query "CREATE ROLE \"${rolename}\" WITH $(role_properties_should);" | ||||
| 				psql_set_password | ||||
| 				;; | ||||
|     absent) | ||||
|         cat << EOF | ||||
| su - '$postgres_user' -c "dropuser \"$name\"" | ||||
| EOF | ||||
| 			(different*) | ||||
| 				if expr "${state_is}" : 'different.*properties' >/dev/null | ||||
| 				then | ||||
| 					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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue