scripts/duplicati/create.homedir.sh

576 lines
17 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
#
# Purpose {{{
# This script will create homedir for members of an LDAP group
# 1. Get members list from LDAP group given as argument
# 2. Compare current list with previous (if it exists)
# 3. Try to create homedir for each user
# 4. Fix permissions on homedir
# 5. Rename members list for next run
#
# 2021-11-19
# }}}
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly PROGDIR=$(readlink -m $(dirname "${0}"))
readonly ARGS="${*}"
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG
# Default values for some vars
readonly LDAP_GROUP_BASE_DEFAULT="ou=grouper,dc=univ-rennes1,dc=fr"
readonly LDAP_SERVER_DEFAULT="ldap://ldap.univ-rennes1.fr"
if [ -f /etc/nslcd.conf ]; then
readonly LDAP_PASSWD_CMD_DEFAULT=$(sed -n 's/\(^bindpw \)\(.*\)/\2/p' /etc/nslcd.conf)
readonly LDAP_USER_CMD_DEFAULT=$(sed -n 's/\(^binddn \)\(.*\)/\2/p' /etc/nslcd.conf)
fi
readonly HOME_BASE_DEFAULT="/home"
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- EOF
usage: $PROGNAME [-b|-d|-g|-h|-p|-s|-u]
Create homedir for members of the given LDAP group.
EXAMPLES:
- Create homedir for members of "ldap:group:my_group"
${PROGNAME} --group "ldap:group:my_group"
- Use default SSSD user for ldap requests
${PROGNAME} --user-cmd "sed -n 's/\(^ldap_default_bind_dn = \)\(.*\)/\2/p' /etc/sssd/sssd.conf"
- Create new homedir in a specific path (/mnt/home.remote)
${PROGNAME} --home "/mnt/home.remote"
OPTIONS:
-b,--base LDAP_BASE
Set different LDAP base (default: ${LDAP_GROUP_BASE_DEFAULT}).
-d,--debug
Enable debug messages.
-g,--group LDAP_GROUP_CN
Required.
LDAP group to parse in order to get the list of homedir to create
to create.
-h,--home,--home-base
Base directory to use for user's home directory
(default: ${HOME_BASE_DEFAULT}).
--help
Print this help message.
-p,--password,--password-cmd "sed -n … /etc/…"
Command to get LDAP bind password from a file (by default,
works with NSLCD /etc/nslcd.conf).
-s,--server ldap://ldap.domain.tld
LDAP url to use for ldapsearch request
(default: ${LDAP_SERVER_DEFAULT}).
-u,--user,--user-cmd "sed -n … /etc/…"
Command to get LDAP bind user from a file (by default,
works with NSLCD /etc/nslcd.conf).
EOF
}
# }}}
debug_message() { # {{{
local_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_message}"
unset local_message
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print error message
printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}"
unset local_error_message
exit "${local_error_code:=66}"
}
# }}}
define_vars() { # {{{
# If ldap_group_cn wasn't defined (argument) {{{
if [ -z "${ldap_group_cn}" ]; then
## Keep it empty
ldap_group_cn=""
fi
# }}}
# If ldap_group_base wasn't defined (argument) {{{
if [ -z "${ldap_group_base}" ]; then
## Use default value
ldap_group_base="${LDAP_GROUP_BASE_DEFAULT}"
fi
# }}}
# If ldap_server wasn't defined (argument) {{{
if [ -z "${ldap_server}" ]; then
## Use default value
ldap_server="${LDAP_SERVER_DEFAULT}"
fi
# }}}
# If ldap_passwd wasn't defined (argument) {{{
if [ -z "${ldap_passwd}" ]; then
## Use default command
ldap_passwd="${LDAP_PASSWD_CMD_DEFAULT}"
debug_message "Use default command to get LDAP password."
fi
# }}}
# If ldap_user wasn't defined (argument) {{{
if [ -z "${ldap_user}" ]; then
## Use default command
ldap_user="${LDAP_USER_CMD_DEFAULT}"
debug_message "Use default command to get LDAP user."
fi
# }}}
# If home_base wasn't defined (argument) {{{
if [ -z "${home_base}" ]; then
## Use default value
home_base="${HOME_BASE_DEFAULT}"
fi
# }}}
## Temp file vars {{{
readonly ldap_user_list_path="/tmp/${PROGNAME}.ldap.user.list"
readonly ldap_previous_user_list_path="/tmp/.${PROGNAME}.previous.ldap.user.list"
## }}}
}
# }}}
is_var_empty() { # {{{
## Return False by default
return_var_empty="1"
## Total number of variables to test
local_total_var="${#}"
loop_count_var_empty="0"
## While it remains a variable to test
while [ "${local_total_var}" -gt "${loop_count_var_empty}" ]; do
debug_message "is_var_empty \
Test var: ${1}."
### Test if this is empty and set return value to True
[ -z "${1}" ] && return_var_empty="0"
### Increase the number of tested variables
loop_count_var_empty=$((loop_count_var_empty+1))
### Shift to the next variable
shift
done
unset local_total_var
unset loop_count_var_empty
return "${return_var_empty}"
}
# }}}
is_var_empty_silent() { # {{{
## Return False by default
return_var_empty_silent="1"
## Total number of variables to test
local_total_var="${#}"
loop_count_var_empty_silent="0"
## While it remains a variable to test
while [ "${local_total_var}" -gt "${loop_count_var_empty_silent}" ]; do
### Test if this is empty and set return value to True
[ -z "${1}" ] && return_var_empty_silent="0"
### Increase the number of tested variables
loop_count_var_empty_silent=$((loop_count_var_empty_silent+1))
### Shift to the next variable
shift
done
unset local_total_var
unset loop_count_var_empty_silent
return "${return_var_empty_silent}"
}
# }}}
is_command_available() { # {{{
local_command_available_cmd="${1}"
## Return False by default
return_command_available="1"
if [ "$(command -v ${local_command_available_cmd})" ]; then
debug_message "is_command_available \
${RED}${local_command_available_cmd}${COLOR_DEBUG} seems present on this host."
return_command_available="0"
else
debug_message "is_command_available \
${RED}${local_command_available_cmd}${COLOR_DEBUG} is not available on this host."
return_command_available="1"
fi
unset local_command_available_cmd
return "${return_command_available}"
}
# }}}
is_directory_absent() { # {{{
local_directory_absent="${1}"
## Directory doesn't exists by default
return_is_directory_absent="0"
### Check if the directory exists
# shellcheck disable=SC2086
if test -d "${local_directory_absent}"; then
return_is_directory_absent="1"
debug_message "is_directory_absent \
The directory ${RED}${local_directory_absent}${COLOR_DEBUG} exists."
else
return_is_directory_absent="0"
debug_message "is_directory_absent \
The directory ${RED}${local_directory_absent}${COLOR_DEBUG} doesn't exist."
fi
unset local_directory_absent
return "${return_is_directory_absent}"
}
# }}}
get_ldap_user_list() { # {{{
## Return False by default
return_get_ldap_user_list="1"
debug_message "get_ldap_user_list \
Create or empty ${RED}${ldap_user_list_path}${COLOR_DEBUG} file to store user list of ${RED}${ldap_group_cn}${COLOR_DEBUG} LDAP group."
true > "${ldap_user_list_path}"
if command ldapsearch -ZZ -D "${ldap_user}" -w "${ldap_passwd}" -H "${ldap_server}" -s one -b "${ldap_group_base}" "(cn=${ldap_group_cn})" member \
| sed -n 's/\(^member: uid=\)\(.*\)\(,ou=.*\)/\2/p' \
| sort > "${ldap_user_list_path}"; then
if [ -s "${ldap_user_list_path}" ]; then
debug_message "get_ldap_user_list \
${RED}${ldap_group_cn}${COLOR_DEBUG} users list successfully created (see ${ldap_user_list_path} file)."
command chmod 0400 -- "${ldap_user_list_path}"
return_get_ldap_user_list="0"
else
debug_message "get_ldap_user_list \
Error, the users list of ${ldap_group_cn} is empty (${ldap_user_list_path} file)."
return_get_ldap_user_list="1"
fi
else
debug_message "get_ldap_user_list \
Error in ${RED}ldapsearch${COLOR_DEBUG} command for ${ldap_group_cn} LDAP group."
return_get_ldap_user_list="1"
fi
return "${return_get_ldap_user_list}"
}
# }}}
is_file_present() { # {{{
local_file_present="${1}"
## File doesn't exist by default
return_is_file_present="1"
### Check if the file exists
# shellcheck disable=SC2086
if find ${local_file_present} > /dev/null 2>&1; then
return_is_file_present="0"
debug_message "is_file_present \
The file ${RED}${local_file_present}${COLOR_DEBUG} exists."
else
return_is_file_present="1"
debug_message "is_file_present \
The file ${RED}${local_file_present}${COLOR_DEBUG} doesn't exist."
fi
unset local_file_present
return "${return_is_file_present}"
}
# }}}
is_file_similar() { # {{{
local_similar_file_one="${1}"
local_similar_file_two="${2}"
## Files aren't similar by default doesn't exist by default
return_is_file_similar="1"
if diff --brief -- "${local_similar_file_one}" "${local_similar_file_two}" > /dev/null; then
debug_message "is_file_similar \
${local_similar_file_one} and ${local_similar_file_two} are ${RED}similar${COLOR_DEBUG}."
return_is_file_similar="0"
else
debug_message "is_file_similar \
${local_similar_file_one} and ${local_similar_file_two} are ${RED}NOT${COLOR_DEBUG} similar."
return_is_file_similar="1"
fi
unset local_similar_file_one
unset local_similar_file_two
return "${return_is_file_similar}"
}
# }}}
create_directory() { # {{{
local_directory="${1}"
## Directory creation fail by default
return_create_directory="1"
if mkdir --parents -- "${local_directory}" > /dev/null; then
debug_message "create_directory \
Successfully create ${RED}${local_directory}${COLOR_DEBUG} directory."
return_create_directory="0"
else
debug_message "create_directory \
Error in 'mkdir' command for ${RED}${local_directory}${COLOR_DEBUG} directory."
return_create_directory="1"
fi
unset local_directory
return "${return_create_directory}"
}
# }}}
fix_directory_permissions() { # {{{
local_directory="${1}"
local_username="${2}"
local_user_groupname="${3}"
## Setting new permissions fail by default
return_fix_directory_permissions="1"
## Change owner {{{
if chown --silent "${local_username}:${local_user_groupname}" -- "${local_directory}" 2> /dev/null; then
debug_message "fix_directory_permissions \
Successfully fix permissions for ${RED}${local_directory}${COLOR_DEBUG} (user: ${local_username})."
## }}}
## Remove group and others permissions {{{
## Cause users might share the same group…
if chmod --silent g-rwx,o-rwx -- "${local_directory}" 2> /dev/null; then
debug_message "fix_directory_permissions \
Successfully remove permissions for group and other on ${RED}${local_directory}${COLOR_DEBUG}."
return_fix_directory_permissions="0"
## }}}
## If something went wrong with chmod or chown {{{
else
debug_message "fix_directory_permissions \
Error in 'chmod' command for ${RED}${local_directory}${COLOR_DEBUG} directory (user: ${local_username})."
return_fix_directory_permissions="1"
fi
## }}}
else
debug_message "fix_directory_permissions \
Error in 'chown' command for ${RED}${local_directory}${COLOR_DEBUG} directory (user: ${local_username})."
return_fix_directory_permissions="1"
fi
unset local_directory
unset local_username
unset local_user_groupname
return "${return_fix_directory_permissions}"
}
# }}}
main() { # {{{
## If ldapsearch command is not available {{{
### exit with message and error
is_command_available "ldapsearch" \
|| error_message "ldapsearch command doesn't seems to be available. Please install ldap-utils package." 1
## }}}
## Define all vars
define_vars
## If ldap_group_cn is empty {{{
### Print help message
### AND exit with message and error
is_var_empty "${ldap_group_cn}" \
&& usage \
&& error_message "Please enter a GROUP with -g|--group option." 10
## }}}
## If ldap_user or ldap_passwd is empty {{{
### Print help message
### AND exit with message and error
is_var_empty_silent "${ldap_user}" "${ldap_passwd}" \
&& usage \
&& error_message "LDAP user or password is empty. Please verify your configuration or the --user-cmd|--passwd-cmd options." 11
## }}}
## If home_base directory doesn't exists {{{
### AND exit with message and error
is_directory_absent "${home_base}" \
&& error_message "Home base directory (${home_base}) doesn't exists. Check your configuration or use -h|--home option." 12
## }}}
## Try to get the user list of LDAP group {{{
### OR Exit
get_ldap_user_list \
|| error_message "Can't get the user list of ${ldap_group_cn} LDAP group. Please use --debug option." 20
## }}}
## If a previous list of users exists {{{
### If the two lists are the same
### Exit
is_file_present "${ldap_previous_user_list_path}" \
&& is_file_similar "${ldap_user_list_path}" "${ldap_previous_user_list_path}" \
&& debug_message "main No new user from previous run, no more actions required." \
&& exit 0
## }}}
## Parse users list {{{
while IFS= read -r username; do
user_groupname=$(id --group -- "${username}" \
|| error_message "Can't get the primary group uid for ${username} user." 21)
### Create user's home directory {{{
### OR Exit
create_directory "${home_base}/${username}" \
|| error_message "Can't create home directory (${home_base}/${username}) for ${username} user. Please use --debug option." 22
### }}}
### Fix permissions for this directory {{{
### OR Exit
fix_directory_permissions "${home_base}/${username}" "${username}" "${user_groupname}" \
|| error_message "Can't fix permissions for ${username} home directory (path: ${home_base}/${username}, username: ${username}, group: ${user_groupname}. Please use --debug option." 23
### }}}
done < "${ldap_user_list_path}"
## }}}
## Information message
debug_message "Create home directory in ${RED}${home_base}${COLOR_DEBUG}, \
for all members of ${RED}${ldap_group_cn},${ldap_group_base}${COLOR_DEBUG} LDAP group \
from ${RED}${ldap_server}${COLOR_DEBUG} LDAP server ."
## Rename user list for next run of the script
## AND exit
mv --force -- "${ldap_user_list_path}" "${ldap_previous_user_list_path}" \
&& exit 0
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
## If the first argument is not an option
if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
then
## Print help message and exit
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
fi
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do
case "${1}" in
-b|--base ) ## Define ldap_group_base
## Move to the next argument
shift
## Define var
readonly ldap_group_base="${1}"
;;
-d|--debug ) ## debug
DEBUG=0
;;
-g|--group ) ## Define ldap_group_cn
## Move to the next argument
shift
## Define var
readonly ldap_group_cn="${1}"
;;
-h|--home|--home-base ) ## Define home_base
## Move to the next argument
shift
## Define var
readonly home_base="${1}"
;;
--help ) ## help
usage
## Exit after help informations
exit 0
;;
-p|--password|--password-cmd ) ## Define ldap_passwd
## Move to the next argument
shift
## Define var
readonly ldap_passwd="${1}"
;;
-s|--server) ## Define ldap_server
## Move to the next argument
shift
## Define var
readonly ldap_server="${1}"
;;
-u|--user|--user-cmd ) ## Define ldap_user
## Move to the next argument
shift
## Define var
readonly ldap_user="${1}"
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "Arguments management \
${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "Arguments management \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "Arguments management \
No arguments/options to manage."
fi
# }}}
main
exit 255