Files
openldap/customer/usr/local/bin/common.sh
T

614 lines
20 KiB
Bash

#!/bin/bash
# Ver: 1.4 by Endial Fang (endial@126.com)
#
# 应用通用业务处理函数
# {0}config
# {-1}frontend
# {1}mdb
# {2}monitor
. /colovu/lib/libcommon.sh # 通用函数库
. /colovu/lib/libfile.sh
. /colovu/lib/libfs.sh
. /colovu/lib/liblog.sh
. /colovu/lib/libos.sh
. /colovu/lib/libservice.sh
. /colovu/lib/libvalidations.sh
# 检测应用相应的配置文件是否存在,如果不存在,则从默认配置文件目录拷贝一份
# 默认配置文件路径:/etc/${APP_NAME}
# 目标配置文件路径:/srv/conf/${APP_NAME}
# 参数:
# $1 - 目标路径
# $2 - 源路径
# $* - 基础路径下的文件及目录列表,以" "分割
# 例子:
# ensure_config_file_exist /etc/${APP_NAME} conf.d server.conf
app_ensure_config_file_exist() {
local -r dist_path="${1:?dist paths is missing}"
local -r base_path="${2:?source paths is missing}"
local f=""
shift 2
LOG_D "List to check in ${base_path}: $@"
while [ "$#" -gt 0 ]; do
f="${1}"
LOG_D " Process \"${f}\""
if [ -d "${base_path}/${f}" ]; then
[[ ! -d "${dist_path}/${f}" ]] && LOG_D " Create directory: ${dist_path}/${f}" && mkdir -p "${dist_path}/${f}"
[[ ! -z $(ls -A "${base_path}/${f}") ]] && app_ensure_config_file_exist "${dist_path}/${f}" "${base_path}/${f}" $(ls -A "${base_path}/${f}")
else
[[ ! -e "${dist_path}/${f}" ]] && LOG_D " Copy: ${base_path}/${f} to ${dist_path}" && cp "${base_path}/${f}" "${dist_path}"
fi
shift
done
}
# 使用环境变量中配置,更新配置文件
app_update_conf() {
LOG_I "Update configure files..."
}
# 生成RootDN用户信息
app_root_credentials() {
# 根据容器参数,设置配置文件
LOG_I "Update RootDN"
cat > "${APP_CONF_DIR}/default_rootdn.ldif" << EOF
# RootDN configration
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: $LDAP_ROOT
-
replace: olcRootDN
olcRootDN: $LDAP_ROOT_DN
-
add: olcRootPW
olcRootPW: $LDAP_ENCRYPTED_ROOT_PASSWORD
EOF
debug_execute ldapmodify -Y EXTERNAL -H "ldapi:///" -f "${APP_CONF_DIR}/default_rootdn.ldif"
}
app_add_default_policy() {
# 根据容器参数,设置配置文件
LOG_I "Add default global access control policy"
cat > "${APP_CONF_DIR}/default_policy.ldif" << EOF
# Add default global access control policy
dn: olcDatabase={2}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" manage
by dn.base="gidNumber=$(id -g ${APP_GROUP})+uidNumber=$(id -u ${APP_NAME}),cn=peercred,cn=external,cn=auth" manage
by dn.base="${LDAP_BIND_DN}" read
by dn.base="${LDAP_ADMIN_DN}" read
by * none
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" manage
by dn.base="gidNumber=$(id -g ${APP_GROUP})+uidNumber=$(id -u ${APP_NAME}),cn=peercred,cn=external,cn=auth" manage
by dn.base="${LDAP_BIND_DN}" read
by dn.base="${LDAP_ADMIN_DN}" write
by * none
dn: olcDatabase={0}config,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" manage
by dn.base="gidNumber=$(id -g ${APP_GROUP})+uidNumber=$(id -u ${APP_NAME}),cn=peercred,cn=external,cn=auth" manage
by dn.base="${LDAP_BIND_DN}" read
by dn.base="${LDAP_ADMIN_DN}" write
by * none
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs="userPassword,sambaLMPassword,sambaNTPassword,sambaPwdLastSet,sambaPwdMustChange,sambaPwdCanChange,shadowMax,shadowExpire"
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" manage
by dn.base="gidNumber=$(id -g ${APP_GROUP})+uidNumber=$(id -u ${APP_NAME}),cn=peercred,cn=external,cn=auth" manage
by dn.base="${LDAP_BIND_DN}" read
by dn.base="${LDAP_ADMIN_DN}" write
by anonymous auth
by self write
by * none
olcAccess: {1}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" manage
by dn.base="gidNumber=$(id -g ${APP_GROUP})+uidNumber=$(id -u ${APP_NAME}),cn=peercred,cn=external,cn=auth" manage
by dn.base="${LDAP_BIND_DN}" read
by dn.base="${LDAP_ADMIN_DN}" write
by anonymous auth
by self write
by * none
EOF
debug_execute ldapmodify -Y EXTERNAL -H "ldapi:///" -f "${APP_CONF_DIR}/default_policy.ldif"
}
# 生成Admin账户用户信息
app_create_tree() {
# 根据容器参数,设置配置文件
LOG_I "Add manager account"
cat > "${APP_CONF_DIR}/default_manager.ldif" << EOF
# Root object creation
dn: $LDAP_ROOT
objectClass: dcObject
objectClass: organization
o: $LDAP_ORGNIZATION_NAME
# Mnanger OU object creation
dn: ou=Manager,$LDAP_ROOT
objectClass: organizationalUnit
ou: Manager
# User Admin object creation
dn: uid=$LDAP_ADMIN_UID,ou=Manager,$LDAP_ROOT
objectClass: inetOrgPerson
cn: $LDAP_ADMIN_GIVEN_NAME $LDAP_ADMIN_SURNAME
sn: $LDAP_ADMIN_SURNAME
uid: $LDAP_ADMIN_UID
userPassword: $LDAP_ENCRYPTED_ADMIN_PASSWORD
mail: $LDAP_ADMIN_MAIL
# User Binder object creation
dn: uid=$LDAP_BIND_UID,ou=Manager,$LDAP_ROOT
objectClass: inetOrgPerson
cn: $LDAP_BIND_GIVEN_NAME $LDAP_BIND_SURNAME
sn: $LDAP_BIND_SURNAME
uid: $LDAP_BIND_UID
userPassword: $LDAP_ENCRYPTED_BIND_PASSWORD
EOF
debug_execute ldapadd -f "${APP_CONF_DIR}/default_manager.ldif" -H "ldapi:///" -D "$LDAP_ROOT_DN" -w "$LDAP_ROOT_PASSWORD"
app_add_default_policy
}
# 生成自定义账户用户信息
app_create_users() {
# 根据容器参数,设置配置文件
LOG_I "Add defined user"
cat > "${APP_CONF_DIR}/default_users.ldif" << EOF
# User OU creation
dn: ${LDAP_USER_OU/#/ou=},$LDAP_ROOT
objectClass: organizationalUnit
ou: users
EOF
read -r -a users <<< "$(tr ',;' ' ' <<< "${LDAP_USERS}")"
read -r -a passwords <<< "$(tr ',;' ' ' <<< "${LDAP_PASSWORDS}")"
local index=0
for user in "${users[@]}"; do
LOG_D " Add user: ${user}"
cat >> "${APP_CONF_DIR}/default_users.ldif" << EOF
# User $user creation
dn: ${user/#/cn=},${LDAP_USER_OU/#/ou=},${LDAP_ROOT}
cn: User$((index + 1 ))
sn: Bar$((index + 1 ))
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
userPassword: ${passwords[$index]}
uid: $user
uidNumber: $((index + 1000 ))
gidNumber: $((index + 1000 ))
homeDirectory: /home/${user}
EOF
index=$((index + 1 ))
done
LOG_D " Add group: ${LDAP_USER_GROUP}"
cat >> "${APP_CONF_DIR}/default_users.ldif" << EOF
# Group creation
dn: ${LDAP_USER_GROUP/#/cn=},${LDAP_USER_OU/#/ou=},${LDAP_ROOT}
cn: $LDAP_USER_GROUP
objectClass: groupOfNames
# User group membership
EOF
for user in "${users[@]}"; do
cat >> "${APP_CONF_DIR}/default_users.ldif" << EOF
member: ${user/#/cn=},${LDAP_USER_OU/#/ou=},${LDAP_ROOT}
EOF
done
debug_execute ldapadd -f "${APP_CONF_DIR}/default_users.ldif" -H "ldapi:///" -D "$LDAP_ROOT_DN" -w "$LDAP_ROOT_PASSWORD"
}
# 生成默认配置文件
app_generate_conf() {
# 根据容器参数,设置配置文件
LOG_I "Creating LDAP online configuration"
debug_execute slapadd -n 0 -F "$LDAP_ONLINE_CONF_DIR" -l "${APP_CONF_DIR}/slapd.ldif"
}
# 生成LTS配置文件
app_generate_lts_conf() {
LOG_I "Configuring TLS"
cat > "${APP_CONF_DIR}/default_certs.ldif" << EOF
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: $LDAP_TLS_CA_FILE
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: $LDAP_TLS_CERT_FILE
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: $LDAP_TLS_KEY_FILE
EOF
if [[ -f "$LDAP_TLS_DH_PARAMS_FILE" ]]; then
cat >> "${APP_CONF_DIR}/default_certs.ldif" << EOF
-
replace: olcTLSDHParamFile
olcTLSDHParamFile: $LDAP_TLS_DH_PARAMS_FILE
EOF
fi
debug_execute ldapmodify -Y EXTERNAL -H "ldapi:///" -f "${APP_CONF_DIR}/default_certs.ldif"
}
# 检测用户参数信息是否满足条件; 针对部分权限过于开放情况,打印提示信息
app_verify_minimum_env() {
local error_code=0
LOG_D "Validating settings in ENV vars..."
print_validation_error() {
LOG_E "$1"
error_code=1
}
check_allowed_port() {
local port_var="${1:?missing port variable}"
local validate_port_args=()
! is_root && validate_port_args+=("-unprivileged")
if ! err=$(validate_port "${validate_port_args[@]}" "${!port_var}"); then
print_validation_error "An invalid port was specified in the environment variable ${port_var}: ${err}."
fi
}
for var in LDAP_SKIP_DEFAULT_TREE LDAP_ENABLE_TLS; do
if ! is_yes_no_value "${!var}"; then
print_validation_error "The allowed values for $var are: yes or no"
fi
done
if is_boolean_yes "$LDAP_ENABLE_TLS"; then
if [[ -z "$LDAP_TLS_CERT_FILE" ]]; then
print_validation_error "You must provide a X.509 certificate in order to use TLS"
elif [[ ! -f "$LDAP_TLS_CERT_FILE" ]]; then
print_validation_error "The X.509 certificate file in the specified path ${LDAP_TLS_CERT_FILE} does not exist"
fi
if [[ -z "$LDAP_TLS_KEY_FILE" ]]; then
print_validation_error "You must provide a private key in order to use TLS"
elif [[ ! -f "$LDAP_TLS_KEY_FILE" ]]; then
print_validation_error "The private key file in the specified path ${LDAP_TLS_KEY_FILE} does not exist"
fi
if [[ -z "$LDAP_TLS_CA_FILE" ]]; then
print_validation_error "You must provide a CA X.509 certificate in order to use TLS"
elif [[ ! -f "$LDAP_TLS_CA_FILE" ]]; then
print_validation_error "The CA X.509 certificate file in the specified path ${LDAP_TLS_CA_FILE} does not exist"
fi
fi
read -r -a users <<< "$(tr ',;' ' ' <<< "${LDAP_USERS}")"
read -r -a passwords <<< "$(tr ',;' ' ' <<< "${LDAP_PASSWORDS}")"
if [[ "${#users[@]}" -ne "${#passwords[@]}" ]]; then
print_validation_error "Specify the same number of passwords on LDAP_PASSWORDS as the number of users on LDAP_USERS!"
fi
if [[ -n "$LDAP_PORT_NUMBER" ]] && [[ -n "$LDAP_LDAPS_PORT_NUMBER" ]]; then
if [[ "$LDAP_PORT_NUMBER" -eq "$LDAP_LDAPS_PORT_NUMBER" ]]; then
print_validation_error "LDAP_PORT_NUMBER and LDAP_LDAPS_PORT_NUMBER are bound to the same port!"
fi
fi
[[ -n "$LDAP_PORT_NUMBER" ]] && check_allowed_port LDAP_PORT_NUMBER
[[ -n "$LDAP_LDAPS_PORT_NUMBER" ]] && check_allowed_port LDAP_LDAPS_PORT_NUMBER
[[ "$error_code" -eq 0 ]] || exit "$error_code"
}
# 以后台方式启动应用服务,并等待启动就绪
app_start_server_bg() {
app_is_server_running && return
local -a flags=("-h" "ldapi:///" "-F" "${APP_CONF_DIR}/slapd.d")
local -r command="$(command -v slapd)"
LOG_I "Starting ${APP_NAME} in background..."
LOG_D "${command} ${flags[@]}"
ulimit -n "${LDAP_ULIMIT_NOFILES}"
debug_execute ${command} "${flags[@]}"
LOG_D "Checking ${APP_NAME} ready status..."
local counter=10
while ! app_is_server_running ; do
LOG_D "Waiting for ${APP_NAME} to ready ... $counter"
if [[ "$counter" -ne 0 ]]; then
break
fi
sleep 1;
counter=$((counter - 1))
done
}
# 停止应用服务
app_stop_server() {
if app_is_server_running ; then
LOG_I "Stopping ${APP_NAME}..."
# 使用 PID 文件 kill 进程
stop_service_using_pid "$LDAP_PID_FILE"
# 检测停止是否完成
LOG_D "Checking ${APP_NAME} running status..."
local counter=10
while [[ "$counter" -ne 0 ]] && app_is_server_running; do
LOG_D "Waiting for ${APP_NAME} to stop ... $counter"
sleep 1
counter=$((counter - 1))
done
fi
}
# 检测应用服务是否在后台运行中
app_is_server_running() {
LOG_D "Check if ${APP_NAME} is running..."
local pid
pid="$(get_pid_from_file '${LDAP_PID_FILE}')"
LOG_D "${APP_NAME} PID: ${pid}"
if [[ -n "${pid}" ]]; then
is_service_running "${pid}"
else
false
fi
}
app_is_server_not_running() {
if [[ app_is_server_running == false ]]; then
true
else
flse
fi
}
# 清理初始化应用时生成的临时文件
app_clean_tmp_file() {
LOG_D "Clean ${APP_NAME} tmp files for init..."
local -r -a files=(
"${LDAP_PID_FILE}"
)
for file in ${files[@]}; do
if [[ -f "$file" ]]; then
LOG_D " Remove $file"
rm "$file"
fi
done
}
# 用户自定义的前置初始化操作,依次执行目录 preinitdb.d 中的初始化脚本
# 执行完毕后,生成文件 ${APP_DATA_DIR}/.custom_preinit_flag
app_custom_preinit() {
LOG_I "Process pre-init for ${APP_NAME}..."
# 检测用户配置文件目录是否存在 preinitdb.d 文件夹,如果存在,尝试执行目录中的初始化脚本
if [ -d "${APP_CONF_DIR}/preinitdb.d" ]; then
# 检测数据存储目录是否存在已初始化标志文件;如果不存在,检索可执行脚本文件并进行初始化操作
if [[ -n $(find "${APP_CONF_DIR}/preinitdb.d/" -type f -regex ".*\.\(sh\)") ]] && \
[[ ! -f "${APP_DATA_DIR}/.custom_preinit_flag" ]]; then
LOG_I "Process custom pre-init scripts from /srv/conf/${APP_NAME}/preinitdb.d..."
# 检索所有可执行脚本,排序后执行
find "${APP_CONF_DIR}/preinitdb.d/" -type f -regex ".*\.\(sh\)" | sort | process_init_files
touch "${APP_DATA_DIR}/.custom_preinit_flag"
echo "$(date '+%Y-%m-%d %H:%M:%S') : Init success." >> "${APP_DATA_DIR}/.custom_preinit_flag"
LOG_I "Custom preinit for ${APP_NAME} complete."
else
LOG_I "Custom preinit for ${APP_NAME} already done before, skipping initialization."
fi
fi
}
# 应用默认初始化操作
# 执行完毕后,生成文件 ${APP_CONF_DIR}/.app_init_flag 及 ${APP_DATA_DIR}/.data_init_flag 文件
app_default_init() {
LOG_I "Process default init for ${APP_NAME}..."
# 检测配置文件是否存在
if [[ ! -f "${APP_CONF_DIR}/.app_init_flag" ]]; then
LOG_I "No injected configuration file found, creating default config files..."
app_generate_conf
touch "${APP_CONF_DIR}/.app_init_flag"
echo "$(date '+%Y-%m-%d %H:%M:%S') : Init success." >> "${APP_CONF_DIR}/.app_init_flag"
else
LOG_I "User injected custom configuration detected!"
LOG_D "Update configure files from environment..."
app_update_conf
fi
if [[ ! -f "${APP_DATA_DIR}/.data_init_flag" ]]; then
LOG_I "Deploying ${APP_NAME} from scratch..."
# 启动后台服务
app_start_server_bg
app_root_credentials
if is_boolean_yes "$LDAP_ENABLE_TLS"; then
app_generate_lts_conf
fi
if is_boolean_yes "$LDAP_SKIP_DEFAULT_TREE"; then
LOG_I "Skipping default schemas/tree structure"
else
# 使用相应的 schemas/tree 初始化 OpenLDAP
app_add_modules
app_add_schemas
if ! is_dir_empty "$LDAP_CUSTOM_SCHEMA_DIR"; then
app_add_custom_schema
fi
if ! is_dir_empty "$LDAP_CUSTOM_LDIF_DIR"; then
app_add_custom_ldifs
else
app_create_tree
app_create_users
fi
fi
touch ${APP_DATA_DIR}/.data_init_flag
echo "$(date '+%Y-%m-%d %H:%M:%S') : Init success." >> ${APP_DATA_DIR}/.data_init_flag
app_is_server_running && app_stop_server
else
LOG_I "Deploying ${APP_NAME} with persisted data..."
fi
}
# 用户自定义的应用初始化操作,依次执行目录initdb.d中的初始化脚本
# 执行完毕后,生成文件 ${APP_DATA_DIR}/.custom_init_flag
app_custom_init() {
LOG_I "Process customer init ${APP_NAME}..."
# 检测用户配置文件目录是否存在 initdb.d 文件夹,如果存在,尝试执行目录中的初始化脚本
if [ -d "${APP_CONF_DIR}/initdb.d" ]; then
# 检测数据存储目录是否存在已初始化标志文件;如果不存在,检索可执行脚本文件并进行初始化操作
if [[ -n $(find "${APP_CONF_DIR}/initdb.d/" -type f -regex ".*\.\(sh\|sql\|sql.gz\)") ]] && \
[[ ! -f "${APP_DATA_DIR}/.custom_init_flag" ]]; then
LOG_I "Process custom init scripts from ${APP_CONF_DIR}/initdb.d..."
# 启动后台服务
app_start_server_bg
# 检索所有可执行脚本,排序后执行
find "${APP_CONF_DIR}/initdb.d/" -type f -regex ".*\.\(sh\|ldif\|ldif.gz\)" | sort | while read -r f; do
case "$f" in
*.sh)
if [[ -x "$f" ]]; then
LOG_D "Executing $f"; "$f"
else
LOG_D "Sourcing $f"; . "$f"
fi
;;
*.ldif)
LOG_D "Executing $f";
postgresql_execute "${PG_DATABASE}" "${PG_INITSCRIPTS_USERNAME}" "${PG_INITSCRIPTS_PASSWORD}" < "$f"
;;
*.ldif.gz)
LOG_D "Executing $f";
gunzip -c "$f" | postgresql_execute "${PG_DATABASE}" "${PG_INITSCRIPTS_USERNAME}" "${PG_INITSCRIPTS_PASSWORD}"
;;
*)
LOG_D "Ignoring $f" ;;
esac
done
touch "${APP_DATA_DIR}/.custom_init_flag"
echo "$(date '+%Y-%m-%d %H:%M:%S') : Init success." >> "${APP_DATA_DIR}/.custom_init_flag"
LOG_I "Custom init for ${APP_NAME} complete."
# 检测服务是否运行中;如果运行,则停止后台服务
app_is_server_running && app_stop_server
app_clean_tmp_file
else
LOG_I "Custom init for ${APP_NAME} already done before, skipping initialization."
fi
fi
}
# 增加 schema 文件
app_add_modules() {
local flag_first=true
LOG_I "Add extra modules"
#read -r -a modules <<< "$(tr ',;' ' ' <<< "${LDAP_EXTRA_MODULES}")"
modules=($(echo "${LDAP_EXTRA_MODULES[*]} accesslog" | tr ',;' ' ' | sed 's/ /\n/g' | sort | uniq) )
cat > "${APP_CONF_DIR}/default_modules.ldif" << EOF
dn: cn=module{0},cn=config
changetype: modify
EOF
for module in "${modules[@]}"; do
LOG_D " Add module: ${module}.la"
cat >> "${APP_CONF_DIR}/default_modules.ldif" << EOF
add: olcModuleLoad
olcModuleLoad: ${module}.la
EOF
[[ ! $flag_first ]] && echo "-" >> "${APP_CONF_DIR}/default_modules.ldif"
flag_first=false
done
debug_execute ldapmodify -Y EXTERNAL -H "ldapi:///" -f "${APP_CONF_DIR}/default_modules.ldif"
}
# 增加 schema 文件
app_add_schemas() {
LOG_I "Add extra schemas"
#read -r -a schemas <<< "$(tr ',;' ' ' <<< "${LDAP_EXTRA_SCHEMAS}")"
schemas=($(echo "${LDAP_EXTRA_SCHEMAS[*]} cosine inetorgperson nis samba" | tr ',;' ' ' | sed 's/ /\n/g' | sort | uniq) )
for schema in "${schemas[@]}"; do
LOG_D "Add schema: ${schema}.ldif"
debug_execute ldapadd -Y EXTERNAL -H "ldapi:///" -f "${APP_CONF_DIR}/schema/${schema}.ldif"
done
}
# 增加个性化 schema 文件
app_add_custom_schema() {
LOG_I "Adding custom Schema in $LDAP_CUSTOM_SCHEMA_DIR ..."
#find "$LDAP_CUSTOM_SCHEMA_DIR" -maxdepth 1 \( -type f -o -type l \) -iname '*.ldif' -print0 | sort -z | xargs --null -I{} bash -c ". /usr/local/scripts/libos.sh && debug_execute debug_execute slapadd -F "$LDAP_ONLINE_CONF_DIR" -n 0 -l {} "
find "${APP_CONF_DIR}/${LDAP_CUSTOM_SCHEMA_DIR}" -maxdepth 1 \( -type f -o -type l \) -iname '*.ldif' -print0 | sort -z | while read -r f; do
LOG_D "Add schema: ${schema}.ldif"
debug_execute debug_execute slapadd -F "$LDAP_ONLINE_CONF_DIR" -n 0 -l $f
done
app_stop_server
#while app_is_server_running; do sleep 1; done
app_start_server_bg
}
# 导入 ldif 文件定义的数据
app_add_custom_ldifs() {
LOG_I "Loading custom LDIF files..."
LOG_W "Ignoring LDAP_USERS, LDAP_PASSWORDS, LDAP_USER_OU and LDAP_USER_GROUP environment variables..."
#find "$LDAP_CUSTOM_LDIF_DIR" -maxdepth 1 \( -type f -o -type l \) -iname '*.ldif' -print0 | sort -z | xargs --null -I{} bash -c ". /usr/local/scripts/libos.sh && debug_execute ldapadd -f {} -H 'ldapi:///' -D $LDAP_ROOT_DN -w $LDAP_ROOT_PASSWORD"
find "${APP_CONF_DIR}/${LDAP_CUSTOM_LDIF_DIR}" -maxdepth 1 \( -type f -o -type l \) -iname '*.ldif' -print0 | sort -z | while read -r f; do
LOG_D "Add ldif: ${schema}.ldif"
debug_execute ldapadd -f $f -H 'ldapi:///' -D $LDAP_ROOT_DN -w $LDAP_ROOT_PASSWORD
done
}