#!@l_bash@
##
##  pg_passwd -- PostgreSQL Database Password Changing Utility
##  Copyright (c) 2007-2018 Ralf S. Engelschall <http://engelschall.com/>
##
##  Permission to use, copy, modify, and distribute this software for
##  any purpose with or without fee is hereby granted, provided that
##  the above copyright notice and this permission notice appear in all
##  copies.
##
##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
##  SUCH DAMAGE.
##

#   determine system username
system_username="`(id -un) 2>/dev/null`"
if [ ".$system_username" = . ]; then
    str="`(id) 2>/dev/null`"
    if [ ".`echo $str | grep '^uid[ 	]*=[ 	]*[0-9]*('`" != . ]; then
        system_username=`echo $str | sed -e 's/^uid[ 	]*=[ 	]*[0-9]*(//' -e 's/).*$//'`
    fi
    if [ ".$system_username" = . ]; then
        system_username="$LOGNAME"
        if [ ".$system_username" = . ]; then
            system_username="$USER"
            if [ ".$system_username" = . ]; then
                system_username="`(whoami) 2>/dev/null | awk '{ printf("%s", $1); }'`"
                if [ ".$system_username" = . ]; then
                    system_username="`(who am i) 2>/dev/null | awk '{ printf("%s", $1); }'`"
                fi
            fi
        fi
    fi
fi

#   determine database superuser username, password and database
superuser_username=""
superuser_password=""
superuser_database=""
superuser_config_file="@l_prefix@/var/postgresql/db/pg_superuser.conf"
if [ -r $superuser_config_file ]; then
    #   read information
    eval `. $superuser_config_file; \
          echo superuser_database=\"$superuser_database\"; \
          echo superuser_username=\"$superuser_username\"; \
          echo superuser_password=\"$superuser_password\"`
else
    #   guess information
    superuser_username="postgresql"
    superuser_database="template1"
fi

#   determine requested username, database and hostname
username="$1"
database="$2"
hostname="$3"
if [ ".$username" = . ]; then
    if [ ".$system_username" = ".root" -o ".$system_username" = ".@l_rusr@" ]; then
        username="$superuser_username"
    else
        username="$system_username"
    fi
fi
if [ ".$database" = . ]; then
    if [ ".$username" = ".$superuser_username" ]; then
        database="$superuser_database"
    else
        database="$username"
    fi
fi
if [ ".$hostname" = . ]; then
    hostname="localhost"
fi

#   make sure that the PostgreSQL super-user password
#   can be kept in sync with the external storage
if [ ".$username" = ".$superuser_username" -a \
     ".$database" = ".$superuser_database" ]; then
   if [ ".$system_username" != ".root" -a ".$system_username" != ".@l_rusr@" ]; then
       echo "$0:ERROR: super-user account password can be changed by \"root\" and \"@l_rusr@\" only" 2>&1
       exit 1
   fi
   if [ -h $superuser_config_file ]; then
       echo "$0:ERROR: superuser config \"$superuser_config_file\": invalid (symbolic link)" 2>&1
       exit 1
   fi
   if [ ! -f $superuser_config_file ]; then
       echo "$0:WARNING: superuser config \"$superuser_config_file\": not existing" 2>&1
       exit 1
   elif [ ! -w $superuser_password_file ]; then
       echo "$0:ERROR: superuser config \"$superuser_config_file\": permission denied (not writeable)" 2>&1
       exit 1
   fi
fi

#   request old and new password
password_old=""
password_new=""
password_new_verify=""
if [ ".$username" = ".$superuser_username" -a \
     ".$database" = ".$superuser_database" ]; then
    password_old="$superuser_password"
fi
while [ ".$password_old" = . ]; do
    read -s -p "$username:$database:$hostname OLD password: " password_old
    echo ""
done
while [ ".$password_new" = . ]; do
    read -s -p "$username:$database:$hostname NEW password: " password_new
    echo ""
done
while [ ".$password_new_verify" = . ]; do
    read -s -p "$username:$database:$hostname NEW password (retype to verify): " password_new_verify
    echo ""
done
if [ ".$password_new" != ".$password_new_verify" ]; then
    echo "$0:ERROR: mismatch on NEW password" 1>&2
    exit 1
fi

#   change the password
echo "ALTER ROLE $username WITH PASSWORD '$password_new'" | \
PGPASSWORD="$password_old" @l_prefix@/bin/psql \
    -q -U $username -d $database -h $hostname -f- || exit $?

#   update superuser configuration
if [ ".$username" = ".$superuser_username" -a \
     ".$database" = ".$superuser_database" ]; then
    (   umask 077
        sed -e "s;.*\(superuser_password=\"\).*\(\"\).*;\1$password_new\2;" \
            <$superuser_config_file >$superuser_config_file.new || exit $?
        cp $superuser_config_file.new $superuser_config_file || exit $?
        rm -f $superuser_config_file.new || exit $?
        exit 0
    ) || {
        echo "$0:ERROR: \"$superuser_config_file\": failed to update content" 1>&2
        rm -f $superuser_config_file.new || true
        exit $?
    }
    (   superuser_database_old="$superuser_database"
        superuser_username_old="$superuser_username"
        superuser_password_old="$superuser_password"
        . $superuser_config_file
        [ ".$superuser_database" != ".$superuser_database_old" ] && exit 1
        [ ".$superuser_username" != ".$superuser_username_old" ] && exit 1
        [ ".$superuser_password"  = ".$superuser_password_old" ] && exit 1
        [ ".$superuser_password" != ".$password_new"           ] && exit 1
        exit 0
    ) || {
        echo "$0:ERROR: \"$superuser_config_file\": unexpected updated content" 1>&2
        exit $?
    }
    (   if [ ".$system_username" = ".root" ]; then
            chown @l_rusr@:@l_rgrp@ $superuser_config_file || exit $?
        fi
        chmod 600 $superuser_config_file || exit $?
        exit 0
    ) || {
        echo "$0:ERROR: \"$superuser_config_file\": failed to fixate attributes" 1>&2
        exit $?
    }
fi

