#!/bin/bash
#
# ======================================================
# VI editor settings
# set shiftwidth=4
# set tabstop=4
# ======================================================
# Title: IPMI functions - LPMI/LOM access and account maintanence functions used by all ipmi scripts
# Author: Mike Gore
# Date: 25 Oct 2016
# Depends: package: openipmi, Scripts: common_host,common_vars,common_functions and NODES found in /usr/local/bin
# Scripts: see cscf-adm@asimov.uwaterloo.ca:/cscf-adm/ipmi
#   common_functions
#      common bash functions/tools
#      includes common_vars and common_host
#   common_vars
#      Global / Institutional default settings defined as shell variables
#   common_host
#      Host specific variables dettings - defined as shell variables - can override any common_vars settings
#   ipmifunctions
#       ipmi bash functions used by all ipmi scripts documented here
#
# Example: update admin password and cscf-adm password - see ipmiusermod for a full example
#  . ipmifunctions
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_default_accounts
#  set_admin_password change
#  set_user_passwords
#  if [ -n "$OLDADMINPASS" ]
#  then
#  	usermod "$ADMIN" "$OLDADMINPASS" "$ADMIN" "$ADMINPASS"
#  else
#  	usermod "$ADMIN" "$ADMINPASS" "$ADMIN" "$ADMINPASS"
#  fi
#  updatepriv
#  if [ -n "$CSCFADM" ]
#  then
#  	usermod "$ADMIN" "$ADMINPASS"  "$CSCFADM" "$CSCFADMPASS"
#  fi
# ======================================================

. common_functions

# ======================================================
# Function: Set default account names for CSCFAND and OTHER
# Arguments: none
# Notes: common_host / common_vars should define these accounts
#       This function is ONLY for STANDALONE use outside of a cluster context
# Vars:
# CSCFADM - Name of default CSCF ADMIN user
# OTHERUSER - Name of optional other userid or blank - typically a cluster user for cluster admins
# Depends: common_functions - optional common_vars and common_host
# Example: 
#  . ipmifunctions
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_default_accounts
set_default_accounts()
{
	# ======================================================
	# Must have an ADMIN user at this point
	if [ -z "$ADMIN" ]
	then
		ADMIN="ADMIN"
	fi

	#We want a CSCFADM USER
	if [ -z "$CSCFADM" ]
	then
		CSCFADM="cscf-adm"
	fi

	# We can have an OTHERUSER set for the cluster
	if [ -z "$OTHERUSER" ]
	then
		#file common_host can define this user
		echo "OTHERUSER is not set for this cluster"
	fi
}

# ======================================================
# Function: check if LOM is up and set the ipmitool options for remote access
# Arguments: LOM IP address or name
#            fatal error if LOM is not specified
# Returns:
# LOMHOST - used by ipmitool
# LOM - LOM hostname or IP address
# Depends: common_functions - optional common_vars and common_host
# Example: 
#  . ipmifunctions
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
lom_check()
{
	LOM="$1"
	if [ -z "$LOM" ]
	then
		fatal "Expected node ILOM name"
	fi
	LOMHOST=

	# CHeck if the host is up
	if ! ping -c 1 -w 1 "$LOM" 2>/dev/null >/dev/null
	then
		echo "Node $LOM is down"
		export LOMHOST LOM
		return 1
	else
		echo "Node $LOM is up"
	fi

	# ipmitool host access arguments
	if [ "$LOM" = "localhost" ]
	then
		# Local access direct to to interface
		LOMHOST=""
	else
		# remote access
		LOMHOST="-I lanplus -H $LOM"
	fi
	export LOMHOST LOM
	return 0
}
# ======================================================
# Function: Update channel 1 access levels
# Arguments: none
# LOMHOST - set by lom_check 
# ADMIN - admin user id - set by set_admin_password
# ADMINPASS - admin password - set by set_admin_password
# fatal error if passwords or ILOM is offline
# Depends: common_functions - optional common_vars and common_host
#          set_admin_password, lom_check
# Example: 
#  . ipmifunctions
# Example:
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_admin_password 
#  updatepriv
updatepriv()
{
	echo Set channel 1 priviledge level
	# Privilege Levels:
	#    1:Callback level, 2:User level, 3: Operator level, 4:Administrator level
	if ! ipmitool $LOMHOST -U "$ADMIN" -P "$ADMINPASS" channel setaccess 1 4 callin=on link=on ipmi=on link=on privilege=4
	then
		fatal "failed to change channel 1 level"
	fi
}
# ======================================================
# Function: list ILOM users and access levels
# Arguments: none
# Notes: used by usermod function to modify ILOM account
#        Does NOT prompt for any variables that are already set 
# LOMHOST - set by lom_check function
# ADMIN - admin user id - - set by set_admin_password
# ADMINPASS - admin password -- set by set_admin_password
# Depends: common_functions - optional common_vars and common_host
#          set_admin_password, lom_check
# Example: 
#  . ipmifunctions
# Example:
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_admin_password 
#  listusers
listusers()
{
	if ! ipmitool $LOMHOST -U $ADMIN -P $ADMINPASS user list 1
	then
		fatal "failed to list users"
	fi
}

# ======================================================
# Function: modify and existing, or create a new user and password
# Arguments: 
#        arg#1 - admin name
#        arg#2 - admin password
#        arg#3 - username
#        arg#4 - user password
# Depends: set_admin_password, set_user_passwords
# Returns:
# USERNUM = numeric userid of user
# USERNEXT = numeric userid of next free unused user slot number
# USERNAME = username
# USERPASS = userpass
# Notes:
#  admin name, admin password, username and user password must exist or fatal exit is raised
# Depends: common_functions - optional common_vars and common_host
#          set_admin_password, lom_check
# Example:
#  . ipmifunctions
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_default_accounts
#  set_admin_password change
#  set_user_passwords
#  if [ -n "$OLDADMINPASS" ]
#  then
#  	usermod "$ADMIN" "$OLDADMINPASS" "$ADMIN" "$ADMINPASS"
#  else
#  	usermod "$ADMIN" "$ADMINPASS" "$ADMIN" "$ADMINPASS"
#  fi
#  updatepriv
usermod()
{
	AUSER="$1"
	APASS="$2"
	USERNAME="$3"
	USERPASS="$4"

	if [ -z "$AUSER" ]
	then
		fatal "$FUNCNAME $AUSER name is missing
	fi

	if [ -z "$APASS" ]
	then
		fatal "$FUNCNAME $AUSER password is missing
	fi

	if [ -z "$USERNAME" ]
	then
		fatal "$FUNCNAME user name is missing
	fi

	if [ -z "$USERPASS" ]
	then
		fatal "$FUNCNAME user password is missing
	fi

	# User number of $USERNAME
	USERNUM=$(ipmitool $LOMHOST -U "$AUSER" -P "$APASS" user list 1 | grep -w "$USERNAME" | grep "^[0-9][0-9]*" | cut -d' ' -f1)
	# Next free user number
	NEXTNUM=$(ipmitool $LOMHOST -U "$AUSER" -P "$APASS" user list 1 | grep "^[0-9][0-9]*" | cut -d' ' -f1 | tail -1 | tr '\n' ' ')
	NEXTNUM=$(($NEXTNUM + 1))

	# Debugging
	echo "USERNAME:[$USERNAME] = $USERNUM"
	#echo "USERNUM:[$USERNUM]"
	#echo "NEXTNUM:[$NEXTNUM]"


	# Do NOT change the ADMIN user name
	if [ "$AUSER" != "$USERNAME" ]
	then
		# If the user does not exist - then add them
		if [ -z "$USERNUM" ]
		then
			echo "$USERNAME not found - creating"
			USERNUM="$NEXTNUM"
		else
			echo "$USERNAME found - updating"
		fi
		# Set user Name
		if ! ipmitool $LOMHOST -U "$AUSER" -P "$APASS" user set name "$USERNUM" "$USERNAME"
		then
			fatal "user set name failed for $USERNAME"
		fi
	else
		if [ -z "$USERNUM" ]
		then
			fatal "$AUSER not found"
		fi
	fi


	# Set Privilege Levels
	#  1:Callback level, 2:User level, 3: Operator level, 4:Administrator level
	# priv <userid> <privilege level> [<channel number>]
	if ! ipmitool $LOMHOST -U "$AUSER" -P "$APASS" user priv "$USERNUM" 4 1
	then
		warn "user privilage update failed for $USERNAME"
	fi

	# Enable user
	if ! ipmitool $LOMHOST -U "$AUSER" -P "$APASS" user enable "$USERNUM"
	then
		warn "user enable failed for $USERNAME"
	fi

	# We always must change the password LAST in case we are changing our own password
	if ! ipmitool $LOMHOST -U "$AUSER" -P "$APASS" user set password "$USERNUM" "$USERPASS"
	then
		fatal "user password change failed for $USERNAME"
	fi

	export USERNAME USERPASS USERNUM NEXTNUM
}

# ======================================================
# Function: prompt for ADMIN account password 
# Arguments: [change] - optionally prompt for new and old password
# Notes: used by usermod function to modify ILOM accounts
#        Does NOT prompt for any variables that are already set 
# Vars:
# ADMIN - Name of default ADMIN user
# ADMINPASS - Password of Admin user
# OLDADMINPASS - Original password of Admin user if change option specified
# Returns
# ADMIN - Name of default ADMIN user
# ADMINPASS - Password of Admin user
# OLDADMINPASS - Original password of Admin user if change option specified
# Depends: common_functions - optional common_vars and common_host
#          set_admin_password, lom_check
# Example: 
#  . ipmifunctions
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_admin_password
set_admin_password()
{
	CHANGE="$1"
	
	#FIXME when setting passwords we should really prompt twice
	# Set our default account names

	# Original ADMIN password
	# We can optionall set this to $ADMINPASS to skip this prompt
	if [ -n "$CHANGE" ]
	then
		if [ -z "$OLDADMINPASS" ]
		then
			uprompt -s "Enter OLD $ADMIN ILOM password"
			export OLDADMINPASS="$USER_PROMPT"
		fi
		if [ -z "$ADMINPASS" ]
		then
			uprompt -s "Enter NEW $ADMIN ILOM password - if different" "$OLDADMINPASS"
			export ADMINPASS="$USER_PROMPT"
		fi
	else
		if [ -z "$ADMINPASS" ]
		then
			uprompt -s "Enter $ADMIN ILOM password"
			export ADMINPASS="$USER_PROMPT"
			export OLDADMINPASS="$ADMINPASS"
			export 
		fi
	fi

	# Prompt for ADMIN 
	# Note: We set ADMIN to avoid being prompted for the ADMIN username
	if [ -z "$ADMINPASS" ]
	then
		fatal "$ADMIN password is NOT set"
	fi
	export ADMIN ADMINPASS OLDADMINPASS
}

# ======================================================
# Function: prompt for CSCFADM and OTHER user
# Arguments: none
# Notes: Used by usermod function to modify ILOM accounts
#        Does NOT prompt if CSCFADM or OTHERUSER are empty
#        Does NOT prompt for any variables that are already set 
#    
# Vars:
# CSCFADM - CSCF Admin user - default is: cscf-adm
# CSCFADMPASS - CSCF Amdin password
# OTHERUSER - Cluster Admin - if not set or empty the other user is NOT created
# OTHERPASS - Cluster Admin password
# Returns:
# CSCFADM - CSCF Admin user - default is: cscf-adm
# CSCFADMPASS - CSCF Amdin password
# OTHERUSER - Cluster Admin - if not set or empty the other user is NOT created
# OTHERPASS - Cluster Admin password
# Depends: common_functions - optional common_vars and common_host
#          set_admin_password, lom_check
# Example: 
#  . ipmifunctions
#  if ! lom_check "$1"
#  then
#  	fatal "LOM $1 is not responding"
#  fi
#  set_admin_password
#  set_user_passwords
set_user_passwords()
{
	# Set passwords for ADMIN, CSCFADM user, and optional OTHERUSER
	if [ -n "$CSCFADM" ]
	then
		# Get CSCFADM password
		# CSCF-ADM user
		if [ -z "$CSCFADMPASS" ]
		then
			uprompt -s "Enter password for $CSCFADM user on ILOM" 
			export CSCFADMPASS="$USER_PROMPT"
			if [ -z "$USER_PROMPT" ]
			then
				fatal "$CSCFADM user must not have blank password"
			fi
		fi
	fi
	export CSCFADM CSCFADMPASS

	# Other user
	if [ -n "$OTHERUSER" ]
	then
		#Optional Cluster Admin, ie. NOT cscf-adm or ADMIN
		if [ -z "$OTHERPASS" ]
		then
			uprompt -s "Enter password for $OTHERUSER user on ILOM"
			export OTHERPASS="$USER_PROMPT"
			if [ -z "$USER_PROMPT" ]
			then
				fatal "$OTHERUSER user must not have blank password"
			fi
		fi
	fi
	export OTHERUSER OTHERPASS
}
# ======================================================