diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-allclear.sh b/src/ldap-allclear.sh new file mode 100755 index 0000000..2e1890f --- /dev/null +++ b/src/ldap-allclear.sh @@ -0,0 +1,80 @@ +#!/bin/bash +######################################################################## +## Script : ldap-allclear.sh +## Name : LDAP のデータを全て削除して初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-allclear.sh [オプション] +## | +## | LDAP のデータを全て削除して、初期化します。 +## | +## |[オプション] +## | -y 問い合わせに対して全て Yes で答えます。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +NO_CONFIRM=n + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-y') NO_CONFIRM=y; shift 1 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + + + +confirm "Remove all LDAP data. Is it OK?" n +if [ $? -eq 1 ]; then + service slapd stop + rm -rf /etc/ldap/slapd.d/* + rm -rf /var/lib/ldap/* + if [ "${NO_CONFIRM}" = "y" ]; then + echo "Removed All LDAP data." + echo "Run the following command as root:" + echo "dpkg-reconfigure slapd" + echo "service slapd start" + else + dpkg-reconfigure slapd + service slapd start + fi +fi + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-allclear.sh b/src/ldap-allclear.sh new file mode 100755 index 0000000..2e1890f --- /dev/null +++ b/src/ldap-allclear.sh @@ -0,0 +1,80 @@ +#!/bin/bash +######################################################################## +## Script : ldap-allclear.sh +## Name : LDAP のデータを全て削除して初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-allclear.sh [オプション] +## | +## | LDAP のデータを全て削除して、初期化します。 +## | +## |[オプション] +## | -y 問い合わせに対して全て Yes で答えます。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +NO_CONFIRM=n + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-y') NO_CONFIRM=y; shift 1 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + + + +confirm "Remove all LDAP data. Is it OK?" n +if [ $? -eq 1 ]; then + service slapd stop + rm -rf /etc/ldap/slapd.d/* + rm -rf /var/lib/ldap/* + if [ "${NO_CONFIRM}" = "y" ]; then + echo "Removed All LDAP data." + echo "Run the following command as root:" + echo "dpkg-reconfigure slapd" + echo "service slapd start" + else + dpkg-reconfigure slapd + service slapd start + fi +fi + diff --git a/src/ldap-deluser.sh b/src/ldap-deluser.sh new file mode 100755 index 0000000..f1ada82 --- /dev/null +++ b/src/ldap-deluser.sh @@ -0,0 +1,94 @@ +#!/bin/bash +######################################################################## +## Script : ldap-deluser:.sh +## Name : LDAP よりユーザーを削除します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-deluser.sh [オプション] uid +## | +## | LDAPよりユーザーを削除します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +P_UID= + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_UID}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# 削除 +echo "uid=${P_UID},ou=User,${DOMAIN_DN}" | ldapdelete -D ${ROOT_DN} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-allclear.sh b/src/ldap-allclear.sh new file mode 100755 index 0000000..2e1890f --- /dev/null +++ b/src/ldap-allclear.sh @@ -0,0 +1,80 @@ +#!/bin/bash +######################################################################## +## Script : ldap-allclear.sh +## Name : LDAP のデータを全て削除して初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-allclear.sh [オプション] +## | +## | LDAP のデータを全て削除して、初期化します。 +## | +## |[オプション] +## | -y 問い合わせに対して全て Yes で答えます。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +NO_CONFIRM=n + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-y') NO_CONFIRM=y; shift 1 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + + + +confirm "Remove all LDAP data. Is it OK?" n +if [ $? -eq 1 ]; then + service slapd stop + rm -rf /etc/ldap/slapd.d/* + rm -rf /var/lib/ldap/* + if [ "${NO_CONFIRM}" = "y" ]; then + echo "Removed All LDAP data." + echo "Run the following command as root:" + echo "dpkg-reconfigure slapd" + echo "service slapd start" + else + dpkg-reconfigure slapd + service slapd start + fi +fi + diff --git a/src/ldap-deluser.sh b/src/ldap-deluser.sh new file mode 100755 index 0000000..f1ada82 --- /dev/null +++ b/src/ldap-deluser.sh @@ -0,0 +1,94 @@ +#!/bin/bash +######################################################################## +## Script : ldap-deluser:.sh +## Name : LDAP よりユーザーを削除します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-deluser.sh [オプション] uid +## | +## | LDAPよりユーザーを削除します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +P_UID= + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_UID}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# 削除 +echo "uid=${P_UID},ou=User,${DOMAIN_DN}" | ldapdelete -D ${ROOT_DN} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + diff --git a/src/ldap-init.sh b/src/ldap-init.sh new file mode 100755 index 0000000..7cabaff --- /dev/null +++ b/src/ldap-init.sh @@ -0,0 +1,258 @@ +#!/bin/bash +######################################################################## +## Script : ldap-init.sh +## Name : LDAP を初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-init.sh [オプション] +## | +## | LDAP を初期化します。 +## | 初期化の際、ユーザー管理のための次のエントリを追加します。 +## | -Group (dn: ou=Group,) +## | -User (dn: ou=User,) +## | +## |[オプション] +## | --id arg 管理者用のIDを設定します。(デフォルト:root)) +## | --password arg 管理者用のパスワードを設定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_ID=root +ROOT_PW= +ROOT_CPW= +TMP_LDIF= + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP の設定を変更する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_change_config() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: olcDatabase={0}config,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcSuffix +olcSuffix: ${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootPW +olcRootPW: ${ROOT_CPW} + +EOF +} + + + +# ====================================================================== +# LDAP のルートDNを設定する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_add_rootdn() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: cn=${ROOT_ID},${DOMAIN_DN} +objectClass: organizationalRole +objectClass: simpleSecurityObject +cn: ${ROOT_ID} +description: LDAP Administrator +userPassword: ${ROOT_CPW} + +dn: ou=Group,${DOMAIN_DN} +objectClass: organizationalUnit +ou: Group + +dn: ou=User,${DOMAIN_DN} +objectClass: organizationalUnit +ou: User + +EOF +} + + + +# ====================================================================== +# アクセス制御の設定を設定ファイルに反映します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +update_ldapconf() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + + LDAP_CONF=/etc/ldap/ldap.conf + CONFIG_HEADER="#@ >>> ----- ACL Auto Settings -----" + CONFIG_FOOTER="#@ <<< ----- ACL Auto Settings -----" + + cp -f "${LDAP_CONF}" "${LDAP_CONF}.old" + sed -e "/${CONFIG_HEADER}/,/${CONFIG_FOOTER}/d" ${LDAP_CONF}.old > ${LDAP_CONF} + +cat << EOF >> ${LDAP_CONF} +${CONFIG_HEADER} +access to * + by self write + by dn="cn=${ROOT_ID},${DOMAIN_DN}" + +access to attr=userPassword + by self write + by dn="cn=${ROOT_ID},${ROMAIN_DN}" + by anonymous auth + by * none + +${CONFIG_FOOTER} + +EOF +} + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + '--id') ROOT_ID="$2"; shift 2 ;; + '--password') ROOT_PW="$2"; shift 2 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + usage + exit 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_ID}" = "" ] && read -p "Root ID > " ROOT_ID +if [ "${ROOT_PW}" = "" ]; then + confirm_password "Root Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + ROOT_PW=${CONFIRM_PASSWORD} +fi + +[ "${DOMAIN}" != "" ] && DOMAIN_DN=`domainToDN ${DOMAIN}` +ROOT_CPW=`slappasswd -h '{CRYPT}' -c '$6$}' -s ${ROOT_PW}` +ROOT_DN_ORIG=`getRootDN` + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-init.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-init.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# LDAP の設定を変更する。 +# ---------------------------------------------------------------------- +echo "### --- Update LDAP Config ---" +mkldif_for_change_config ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +debug_pause + +# ---------------------------------------------------------------------- +# 古い情報を削除する +# ---------------------------------------------------------------------- +echo "### --- Delete Old LDAP Informations ---" +echo "ou=Group,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "ou=User,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "${ROOT_DN_ORIG}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# ルートDNを設定する。 +# ---------------------------------------------------------------------- +echo "### --- Add LDAP Informations (Group, User) ---" +mkldif_for_add_rootdn ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -D cn=${ROOT_ID},${DOMAIN_DN} -f ${TMP_LDIF} -a -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# 設定ファイルを更新する。 +# ---------------------------------------------------------------------- +echo "### --- Update /etc/ldap/ldap.conf" +update_ldapconf ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} +service slapd restart +debug_pause + + +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={0}config,cn=config' oldRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b "${DOMAIN_DN}" + + +rm -f /tmp/ldap-*.*.ldif + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-allclear.sh b/src/ldap-allclear.sh new file mode 100755 index 0000000..2e1890f --- /dev/null +++ b/src/ldap-allclear.sh @@ -0,0 +1,80 @@ +#!/bin/bash +######################################################################## +## Script : ldap-allclear.sh +## Name : LDAP のデータを全て削除して初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-allclear.sh [オプション] +## | +## | LDAP のデータを全て削除して、初期化します。 +## | +## |[オプション] +## | -y 問い合わせに対して全て Yes で答えます。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +NO_CONFIRM=n + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-y') NO_CONFIRM=y; shift 1 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + + + +confirm "Remove all LDAP data. Is it OK?" n +if [ $? -eq 1 ]; then + service slapd stop + rm -rf /etc/ldap/slapd.d/* + rm -rf /var/lib/ldap/* + if [ "${NO_CONFIRM}" = "y" ]; then + echo "Removed All LDAP data." + echo "Run the following command as root:" + echo "dpkg-reconfigure slapd" + echo "service slapd start" + else + dpkg-reconfigure slapd + service slapd start + fi +fi + diff --git a/src/ldap-deluser.sh b/src/ldap-deluser.sh new file mode 100755 index 0000000..f1ada82 --- /dev/null +++ b/src/ldap-deluser.sh @@ -0,0 +1,94 @@ +#!/bin/bash +######################################################################## +## Script : ldap-deluser:.sh +## Name : LDAP よりユーザーを削除します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-deluser.sh [オプション] uid +## | +## | LDAPよりユーザーを削除します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +P_UID= + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_UID}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# 削除 +echo "uid=${P_UID},ou=User,${DOMAIN_DN}" | ldapdelete -D ${ROOT_DN} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + diff --git a/src/ldap-init.sh b/src/ldap-init.sh new file mode 100755 index 0000000..7cabaff --- /dev/null +++ b/src/ldap-init.sh @@ -0,0 +1,258 @@ +#!/bin/bash +######################################################################## +## Script : ldap-init.sh +## Name : LDAP を初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-init.sh [オプション] +## | +## | LDAP を初期化します。 +## | 初期化の際、ユーザー管理のための次のエントリを追加します。 +## | -Group (dn: ou=Group,) +## | -User (dn: ou=User,) +## | +## |[オプション] +## | --id arg 管理者用のIDを設定します。(デフォルト:root)) +## | --password arg 管理者用のパスワードを設定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_ID=root +ROOT_PW= +ROOT_CPW= +TMP_LDIF= + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP の設定を変更する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_change_config() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: olcDatabase={0}config,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcSuffix +olcSuffix: ${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootPW +olcRootPW: ${ROOT_CPW} + +EOF +} + + + +# ====================================================================== +# LDAP のルートDNを設定する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_add_rootdn() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: cn=${ROOT_ID},${DOMAIN_DN} +objectClass: organizationalRole +objectClass: simpleSecurityObject +cn: ${ROOT_ID} +description: LDAP Administrator +userPassword: ${ROOT_CPW} + +dn: ou=Group,${DOMAIN_DN} +objectClass: organizationalUnit +ou: Group + +dn: ou=User,${DOMAIN_DN} +objectClass: organizationalUnit +ou: User + +EOF +} + + + +# ====================================================================== +# アクセス制御の設定を設定ファイルに反映します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +update_ldapconf() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + + LDAP_CONF=/etc/ldap/ldap.conf + CONFIG_HEADER="#@ >>> ----- ACL Auto Settings -----" + CONFIG_FOOTER="#@ <<< ----- ACL Auto Settings -----" + + cp -f "${LDAP_CONF}" "${LDAP_CONF}.old" + sed -e "/${CONFIG_HEADER}/,/${CONFIG_FOOTER}/d" ${LDAP_CONF}.old > ${LDAP_CONF} + +cat << EOF >> ${LDAP_CONF} +${CONFIG_HEADER} +access to * + by self write + by dn="cn=${ROOT_ID},${DOMAIN_DN}" + +access to attr=userPassword + by self write + by dn="cn=${ROOT_ID},${ROMAIN_DN}" + by anonymous auth + by * none + +${CONFIG_FOOTER} + +EOF +} + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + '--id') ROOT_ID="$2"; shift 2 ;; + '--password') ROOT_PW="$2"; shift 2 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + usage + exit 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_ID}" = "" ] && read -p "Root ID > " ROOT_ID +if [ "${ROOT_PW}" = "" ]; then + confirm_password "Root Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + ROOT_PW=${CONFIRM_PASSWORD} +fi + +[ "${DOMAIN}" != "" ] && DOMAIN_DN=`domainToDN ${DOMAIN}` +ROOT_CPW=`slappasswd -h '{CRYPT}' -c '$6$}' -s ${ROOT_PW}` +ROOT_DN_ORIG=`getRootDN` + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-init.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-init.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# LDAP の設定を変更する。 +# ---------------------------------------------------------------------- +echo "### --- Update LDAP Config ---" +mkldif_for_change_config ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +debug_pause + +# ---------------------------------------------------------------------- +# 古い情報を削除する +# ---------------------------------------------------------------------- +echo "### --- Delete Old LDAP Informations ---" +echo "ou=Group,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "ou=User,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "${ROOT_DN_ORIG}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# ルートDNを設定する。 +# ---------------------------------------------------------------------- +echo "### --- Add LDAP Informations (Group, User) ---" +mkldif_for_add_rootdn ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -D cn=${ROOT_ID},${DOMAIN_DN} -f ${TMP_LDIF} -a -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# 設定ファイルを更新する。 +# ---------------------------------------------------------------------- +echo "### --- Update /etc/ldap/ldap.conf" +update_ldapconf ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} +service slapd restart +debug_pause + + +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={0}config,cn=config' oldRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b "${DOMAIN_DN}" + + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-loglevel.sh b/src/ldap-loglevel.sh new file mode 100755 index 0000000..1b962d8 --- /dev/null +++ b/src/ldap-loglevel.sh @@ -0,0 +1,114 @@ +#!/bin/bash +######################################################################## +## Script : ldap-loglevel.sh +## Name : LDAP のログレベル変更スクリプト +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-loglevel.sh [オプション] [LogLevel] +## | +## | LDAP のログレベルを設定します。 +## | LogLevel の指定が無い場合、stats を設定します。 +## | LogLevel には次の Level の値または、Keyword の文字列を指定可能である。 +## | 複数指定する場合は、Level の値を OR した値を指定すれば良い。 +## | +## | Level Level(Hex) Keyword Description +## | -1 any enable all debugging +## | 0 no debugging (ログ出力なし) +## | 1 0x1 trace trace function calls +## | 2 0x2 packets debug packet handling +## | 4 0x4 args heavy trace debugging +## | 8 0x8 conns connection management +## | 16 0x10 BER print out packets sent and received +## | 32 0x20 filter search filter processing +## | 64 0x40 config configuration processing +## | 128 0x80 ACL access control list processing +## | 256 0x100 stats stats log connections/operations/results +## | 512 0x200 stats2 stats log entries sent +## | 1024 0x400 shell print communication with shell backends +## | 2048 0x800 parse print entry parsing debugging +## | 16384 0x4000 sync syncrepl consumer processing +## | 32768 0x8000 none only messages that get logged whatever log level is set +## | +## | 詳細は、https://www.openldap.org/doc/admin24/slapdconfig.html を参照のこと。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +LOG_LEVEL=stats + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP のログレベルを指定されたログレベルに変更する +# ldif 形式のデータを標準出力します。 +# +# @param $1 ログレベル +# ====================================================================== +mkldif_for_change_loglevel() +{ +cat << EOF +dn: cn=config +changeType: modify +replace: olcLogLevel +olcLogLevel: ${LOG_LEVEL} +EOF +} + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + +TMP_LDIF=$(mktemp /tmp/ldap.XXXXXXXXXXXX.ldif) +trap 'rm -f ${TMP_LDIF}; exit 1' 1 2 3 15 + +mkldif_for_change_loglevel ${LOG_LEVEL} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn=config' cn=config + +rm -f ${TMP_LDIF} + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-allclear.sh b/src/ldap-allclear.sh new file mode 100755 index 0000000..2e1890f --- /dev/null +++ b/src/ldap-allclear.sh @@ -0,0 +1,80 @@ +#!/bin/bash +######################################################################## +## Script : ldap-allclear.sh +## Name : LDAP のデータを全て削除して初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-allclear.sh [オプション] +## | +## | LDAP のデータを全て削除して、初期化します。 +## | +## |[オプション] +## | -y 問い合わせに対して全て Yes で答えます。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +NO_CONFIRM=n + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-y') NO_CONFIRM=y; shift 1 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + + + +confirm "Remove all LDAP data. Is it OK?" n +if [ $? -eq 1 ]; then + service slapd stop + rm -rf /etc/ldap/slapd.d/* + rm -rf /var/lib/ldap/* + if [ "${NO_CONFIRM}" = "y" ]; then + echo "Removed All LDAP data." + echo "Run the following command as root:" + echo "dpkg-reconfigure slapd" + echo "service slapd start" + else + dpkg-reconfigure slapd + service slapd start + fi +fi + diff --git a/src/ldap-deluser.sh b/src/ldap-deluser.sh new file mode 100755 index 0000000..f1ada82 --- /dev/null +++ b/src/ldap-deluser.sh @@ -0,0 +1,94 @@ +#!/bin/bash +######################################################################## +## Script : ldap-deluser:.sh +## Name : LDAP よりユーザーを削除します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-deluser.sh [オプション] uid +## | +## | LDAPよりユーザーを削除します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +P_UID= + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_UID}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# 削除 +echo "uid=${P_UID},ou=User,${DOMAIN_DN}" | ldapdelete -D ${ROOT_DN} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + diff --git a/src/ldap-init.sh b/src/ldap-init.sh new file mode 100755 index 0000000..7cabaff --- /dev/null +++ b/src/ldap-init.sh @@ -0,0 +1,258 @@ +#!/bin/bash +######################################################################## +## Script : ldap-init.sh +## Name : LDAP を初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-init.sh [オプション] +## | +## | LDAP を初期化します。 +## | 初期化の際、ユーザー管理のための次のエントリを追加します。 +## | -Group (dn: ou=Group,) +## | -User (dn: ou=User,) +## | +## |[オプション] +## | --id arg 管理者用のIDを設定します。(デフォルト:root)) +## | --password arg 管理者用のパスワードを設定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_ID=root +ROOT_PW= +ROOT_CPW= +TMP_LDIF= + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP の設定を変更する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_change_config() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: olcDatabase={0}config,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcSuffix +olcSuffix: ${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootPW +olcRootPW: ${ROOT_CPW} + +EOF +} + + + +# ====================================================================== +# LDAP のルートDNを設定する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_add_rootdn() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: cn=${ROOT_ID},${DOMAIN_DN} +objectClass: organizationalRole +objectClass: simpleSecurityObject +cn: ${ROOT_ID} +description: LDAP Administrator +userPassword: ${ROOT_CPW} + +dn: ou=Group,${DOMAIN_DN} +objectClass: organizationalUnit +ou: Group + +dn: ou=User,${DOMAIN_DN} +objectClass: organizationalUnit +ou: User + +EOF +} + + + +# ====================================================================== +# アクセス制御の設定を設定ファイルに反映します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +update_ldapconf() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + + LDAP_CONF=/etc/ldap/ldap.conf + CONFIG_HEADER="#@ >>> ----- ACL Auto Settings -----" + CONFIG_FOOTER="#@ <<< ----- ACL Auto Settings -----" + + cp -f "${LDAP_CONF}" "${LDAP_CONF}.old" + sed -e "/${CONFIG_HEADER}/,/${CONFIG_FOOTER}/d" ${LDAP_CONF}.old > ${LDAP_CONF} + +cat << EOF >> ${LDAP_CONF} +${CONFIG_HEADER} +access to * + by self write + by dn="cn=${ROOT_ID},${DOMAIN_DN}" + +access to attr=userPassword + by self write + by dn="cn=${ROOT_ID},${ROMAIN_DN}" + by anonymous auth + by * none + +${CONFIG_FOOTER} + +EOF +} + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + '--id') ROOT_ID="$2"; shift 2 ;; + '--password') ROOT_PW="$2"; shift 2 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + usage + exit 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_ID}" = "" ] && read -p "Root ID > " ROOT_ID +if [ "${ROOT_PW}" = "" ]; then + confirm_password "Root Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + ROOT_PW=${CONFIRM_PASSWORD} +fi + +[ "${DOMAIN}" != "" ] && DOMAIN_DN=`domainToDN ${DOMAIN}` +ROOT_CPW=`slappasswd -h '{CRYPT}' -c '$6$}' -s ${ROOT_PW}` +ROOT_DN_ORIG=`getRootDN` + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-init.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-init.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# LDAP の設定を変更する。 +# ---------------------------------------------------------------------- +echo "### --- Update LDAP Config ---" +mkldif_for_change_config ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +debug_pause + +# ---------------------------------------------------------------------- +# 古い情報を削除する +# ---------------------------------------------------------------------- +echo "### --- Delete Old LDAP Informations ---" +echo "ou=Group,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "ou=User,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "${ROOT_DN_ORIG}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# ルートDNを設定する。 +# ---------------------------------------------------------------------- +echo "### --- Add LDAP Informations (Group, User) ---" +mkldif_for_add_rootdn ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -D cn=${ROOT_ID},${DOMAIN_DN} -f ${TMP_LDIF} -a -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# 設定ファイルを更新する。 +# ---------------------------------------------------------------------- +echo "### --- Update /etc/ldap/ldap.conf" +update_ldapconf ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} +service slapd restart +debug_pause + + +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={0}config,cn=config' oldRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b "${DOMAIN_DN}" + + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-loglevel.sh b/src/ldap-loglevel.sh new file mode 100755 index 0000000..1b962d8 --- /dev/null +++ b/src/ldap-loglevel.sh @@ -0,0 +1,114 @@ +#!/bin/bash +######################################################################## +## Script : ldap-loglevel.sh +## Name : LDAP のログレベル変更スクリプト +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-loglevel.sh [オプション] [LogLevel] +## | +## | LDAP のログレベルを設定します。 +## | LogLevel の指定が無い場合、stats を設定します。 +## | LogLevel には次の Level の値または、Keyword の文字列を指定可能である。 +## | 複数指定する場合は、Level の値を OR した値を指定すれば良い。 +## | +## | Level Level(Hex) Keyword Description +## | -1 any enable all debugging +## | 0 no debugging (ログ出力なし) +## | 1 0x1 trace trace function calls +## | 2 0x2 packets debug packet handling +## | 4 0x4 args heavy trace debugging +## | 8 0x8 conns connection management +## | 16 0x10 BER print out packets sent and received +## | 32 0x20 filter search filter processing +## | 64 0x40 config configuration processing +## | 128 0x80 ACL access control list processing +## | 256 0x100 stats stats log connections/operations/results +## | 512 0x200 stats2 stats log entries sent +## | 1024 0x400 shell print communication with shell backends +## | 2048 0x800 parse print entry parsing debugging +## | 16384 0x4000 sync syncrepl consumer processing +## | 32768 0x8000 none only messages that get logged whatever log level is set +## | +## | 詳細は、https://www.openldap.org/doc/admin24/slapdconfig.html を参照のこと。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +LOG_LEVEL=stats + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP のログレベルを指定されたログレベルに変更する +# ldif 形式のデータを標準出力します。 +# +# @param $1 ログレベル +# ====================================================================== +mkldif_for_change_loglevel() +{ +cat << EOF +dn: cn=config +changeType: modify +replace: olcLogLevel +olcLogLevel: ${LOG_LEVEL} +EOF +} + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + +TMP_LDIF=$(mktemp /tmp/ldap.XXXXXXXXXXXX.ldif) +trap 'rm -f ${TMP_LDIF}; exit 1' 1 2 3 15 + +mkldif_for_change_loglevel ${LOG_LEVEL} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn=config' cn=config + +rm -f ${TMP_LDIF} + diff --git a/src/ldap-showuser.sh b/src/ldap-showuser.sh new file mode 100755 index 0000000..b7f37d5 --- /dev/null +++ b/src/ldap-showuser.sh @@ -0,0 +1,97 @@ +#!/bin/bash +######################################################################## +## Script : ldap-showuser:.sh +## Name : LDAP に登録されているユーザーを表示します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-showuser.sh [オプション] uid +## | +## | LDAPに登録されているユーザーを表示します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password 管理者パスワードを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= + + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +if [ "${P_UID}" = "" ]; then + SEARCH= +else + SEARCH="(uid=${P_UID})" +fi +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} ${SEARCH} + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2b788b --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# LDAP によるユーザー管理スクリプト + +LDAP によりユーザーを管理するためのスクリプト。 +現状、Debian 前提のスクリプトとなっています。 +※ldap-init.sh 以外は、他でも利用可能かと思います。 + diff --git a/lib/bash-utils.sh b/lib/bash-utils.sh new file mode 100755 index 0000000..a99c0b0 --- /dev/null +++ b/lib/bash-utils.sh @@ -0,0 +1,253 @@ +#!/bin/bash +######################################################################## +## Script : bash-utils.sh +## Name : bash 用ユーティリティ関数スクリプト +## Version : 0.0.1 +## Copyright : 2018-2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + + +# ===================================================================== +# 指定されたパスの絶対パスを取得します。 +# +# [注意事項] +# 間にパスが存在しない場合、元の値をそのまま返します。 +# +# @param $1 パス +# @stdout 絶対パス +# ===================================================================== +function getAbsolutePath() +{ + BASE="" + DIR="$1" + if [ ! -d ${DIR} ]; then + BASE="/$(basename "${DIR}")" + DIR=$(dirname "${DIR}") + fi + if [ ! -d ${DIR} ]; then + echo "${DIR}${BASE}" + return 1 + fi + DIR=$(cd "$DIR" && pwd) + echo "${DIR}${BASE}" + return 0 +} +# 途中でカレントディレクトリが変更されても良いように。 +# SCRIPT_FILE を絶対パスに変換しておく。 +SCRIPT_FILE=`getAbsolutePath ${SCRIPT_FILE}` + + + +# ===================================================================== +# スクリプト中の "## [key] : [value]" 形式で記載されている +# プロパティの値([value])を取得します。 +# +# @param $1 key +# @stdout value +# ===================================================================== +function getProperty() { +KEY=${1} +sed -n "s/^##\s*${KEY}\s*\:\s*\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# スクリプトファイルのバージョン情報を出力します。 +# スクリプトファイルには、次のコメント行が必要となります。 +# ※間の空白は無視されます。 +# +# ## Script : スクリプトファイル名 +# ## Version : バージョン番号 +# +# @stdout バージョン情報 +# ===================================================================== +function version() { +SCRIPT=`getProperty "Script"` +VERSION=`getProperty "Version"` +echo "${SCRIPT} ${VERSION}" +} + + +# ===================================================================== +# スクリプトファイルの使用法を出力します。 +# スクリプトファイルには、次の形式の使用法情報が必要となります。 +# ※'## Usage:' ~ '##' 範囲の行で、'## |'より後ろの文字列が、 +# 使用法として表示されます。 +# +# ## Usage: +# ## |使用例) ... +# ## |...(ヘルプ情報)... +# ## |...(ヘルプ情報)... +# ## +# +# @stdout ヘルプ +# ===================================================================== +function usage() { +sed -n "/^##\s*Usage\s*\:\s*/,/^##\s*$/ s/^##\s*|\(.*\)$/\1/p" ${SCRIPT_FILE} +} + + +# ===================================================================== +# 指定されたメッセージと共に y/n を入力させ、結果を返します。 +# y,Y,n,N いずれの文字でも始まらない場合、デフォルト値を返します。 +# +# 変数 ${NO_CONFIRM} が 'y' に設定されている場合、 +# 問い合わせのメッセージを表示することなく、常に 1 を返します。 +# +# @param $1 メッセージ +# @param $2 デフォルト値 (1=y, 0=n) +# @return $? 1/0 (y/n) +# ===================================================================== +function confirm() { + MESSAGE=$1 + DEFAULT=$2 + + if [ "${NO_CONFIRM}" = "y" ]; then + return 1 + fi + + LINE= + read -p "${MESSAGE} [y/n] " LINE + VAL=${LINE:0:1} + if [ "${VAL}" = "y" ] || [ "${VAL}" = "Y" ]; then + return 1 + elif [ "${VAL}" = "n" ] || [ "${VAL}" = "N" ]; then + return 0 + fi + return ${DEFAULT} +} + + +# ===================================================================== +# 指定された値が、指定されたリストに含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContains() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + if [ "${VALUE}" = "${item}" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された値が、指定されたリスト(正規表現)に +# 含まれるか否かを返します。 +# +# @param $1 リスト。 +# @param $2 含まれるか否か検査する値 +# @return $? 1/0 (含まれる/含まれない) +# ===================================================================== +function isContainsRegex() { + LIST=$1 + VALUE=$2 + for item in ${LIST}; do + RES=`echo "${item}" | sed "s/${VALUE}/1/"` + if [ "${RES}" = "1" ]; then + return 1 + fi + done + return 0 +} + + +# ===================================================================== +# 指定された出力先にファイルがある場合、上書きするかを問い合わせ、 +# y が選択された場合、上書きします。 +# n が選択された場合、処理を中断します。 +# +# @param $1 出力先 +# ===================================================================== +function overwrite() { + OUT=$1 + if [ -f ${OUT} ]; then + MSG_PATH=`getAbsolutePath ${OUT}` + confirm "${MSG_PATH} が存在します。上書きしますか?" 0 + if [ $? -eq 0 ]; then + exit 1 + fi + fi +} + + + +# ===================================================================== +# パスワードを入力させます。 +# 確認のため2回パスワード入力を求め、2回のパスワードが +# 一致すれば入力されたパスワードを標準出力し、0 を返します。 +# 不一致の場合は、1 を返します。 +# +# @param $1 パスワード入力メッセージ +# @param $2 パスワード再入力メッセージ +# @stdout 入力されたパスワード +# @return 0/1 (成功/失敗) +# ===================================================================== +CONFIRM_PASSWORD= +function confirmPassword() { + MESSAGE=$1 + MESSAGE_RE=$2 + read -s -p "${MESSAGE}" PASSWORD + echo "" + read -s -p "${MESSAGE_RE}" CONFIRM_PASSWORD + echo "" + RET=1 + if [ "${PASSWORD}" = "${CONFIRM_PASSWORD}" ]; then + CONFIRM_PASSWORD=${PASSWORD} + RET=0 + else + CONFIRM_PASSWORD= + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# 指定されたテンプレートファイル中の変数を環境変数の値で置換し、 +# 標準出力します。 +# +# @param $1 テンプレートファイル +# @stdout 変数が置換されたテンプレートの内容 +# @return 0/1 (成功/失敗[テンプレートファイルが無い]) +# ===================================================================== +function template() { + TMPL_FILE=$1 + RET=0 + if [ -f ${TMPL_FILE} ]; then + while read LINE; do + echo $(eval echo "${LINE}") + done < ${TMPL_FILE} + else + RET=1 + fi + return ${RET} +} + + + +# ===================================================================== +# デバッグ用ステップ実行 +# ${DEBUG} の値が 1 の場合、ポーズします。 +# ===================================================================== +function debugPause() { + if [ "${DEBUG}" = "1" ]; then + read -p "Please [Enter] > " DUMMY_READ + fi +} + diff --git a/src/ldap-addgroup.sh b/src/ldap-addgroup.sh new file mode 100755 index 0000000..1c7f406 --- /dev/null +++ b/src/ldap-addgroup.sh @@ -0,0 +1,230 @@ +#!/bin/bash +######################################################################## +## Script : ldap-addgroup:.sh +## Name : LDAP にグループを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-addgroup.sh [オプション] cn(GroupNamme) +## | +## | LDAPにグループを追加します。 +## | --uid <ユーザーID> が指定された場合、当該グループにユーザーを追加します。 +## | /etc/group に gid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |cn(GroupName) +## | グループIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --uid uid 当該グループに追加するユーザーを指定します。 +## | --gidNumber arg GID番号を指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: cn=<グループ名>,ou=Group,<ドメインのDN> +## | objectClass: posixGroup +## | cn: <グループ名> +## | gidNumber: +## | memberUid: <ユーザーID> +## | +## +## <備考> +## グループ管理として、次のクラスも利用可能であるが、 +## 共存できないため poixGroup のみを利用する。 +## objectClass: groupOfNames +## member: uid=<ユーザーID>,ou=User,<ドメインDN> +## +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_CN= +P_GID_NUMBER= +P_UID= + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定されたグループに関する情報を /etc/group より抽出し、各変数にセットします。 +# ※現状自動抽出する値は、グループ番号のみです。 +# +# @param $1 cn (GroupName) +# ====================================================================== +function load_default_info() +{ + P_CN=$1 + ETC_GROUP=/etc/group + [ "${P_GID_NUMBER}" = "" ] && P_GID_NUMBER=`grep -e "${P_CN}:" ${ETC_GROUP} | awk -F ':' {'print $3'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# グループを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_group() +{ + DOMAIN_DN=$1 + + print_attr dn "cn=${P_CN},ou=Group,${DOMAIN_DN}" + print_attr objectClass "posixGroup" + print_attr cn "${P_CN}" + print_attr gidNumber "${P_GID_NUMBER}" + +} + + +# ====================================================================== +# グループにユーザーを登録するための ldif 形式データを標準出力します。 +# ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user_to_group() +{ + DOMAIN_DN=$1 + +cat << EOF +dn: cn=${P_CN},ou=Group,${DOMAIN_DN} +changetype: modify +add: memberUid +memberUid: ${P_UID} + +EOF + +} + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--uid') P_UID="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_CN=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数チェック +# ---------------------------------------------------------------------- +if [ "${P_CN}" = "" ]; then + usage + exit 1 +fi + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_CN} +fi + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_ROOTPW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-addgroup.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-addgroup.*.ldif; exit 1' 1 2 3 15 + + +# ---------------------------------------------------------------------- +# グループ登録 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b ou=Group,${DOMAIN_DN} -w ${ROOT_PW} "(cn=${P_CN})" | grep "^dn: cn=${P_CN},ou=Group,${DOMAIN_DN}" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "### --- Add Group (cn=${P_CN}) ---" + [ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER + mkldif_for_add_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +if [ "${P_UID}" != "" ]; then + echo "### --- Add User (uid=${P_UID}) ---" + mkldif_for_add_user_to_group ${DOMAIN_DN} > ${TMP_LDIF} + ldapmodify -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} +fi + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +ldapsearch -D ${ROOT_DN} -b cn=${P_CN},ou=Group,${DOMAIN_DN} -w ${ROOT_PW} + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-adduser.sh b/src/ldap-adduser.sh new file mode 100755 index 0000000..7092a1d --- /dev/null +++ b/src/ldap-adduser.sh @@ -0,0 +1,285 @@ +#!/bin/bash +######################################################################## +## Script : ldap-adduser:.sh +## Name : LDAP にユーザーを追加します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-adduser.sh [オプション] uid +## | +## | LDAPにユーザーを追加します。 +## | /etc/passwd, /etc/shadow に uid にマッチする情報があればデフォルト値として使用されます。 +## | デフォルト値を使用しない場合は、--nodefault を指定してください。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password arg 管理者パスワードを指定します。 +## | --nodefault デフォルト値 +## | --sn arg 姓を指定します。 +## | --cn arg 名前(Full Name)を指定します。 +## | --uidNumber arg UID番号を指定します。 +## | --gidNumber arg GID番号を指定します。 +## | --homeDirectory arg ホームディレクトリを指定します。 +## | --loginShell arg ログインシェルを指定します。 +## | --userPassword arg ユーザーパスワードを指定します。 +## | --shadowLastChange arg 最終パスワード変更日時を指定します。 +## | --shadowMin arg パスワード変更不能日数を指定します。 +## | --shadowMax arg パスワード変更要求までの日数を指定します。 +## | --shadowWarning arg パスワード期限満了警告日数を指定します。 +## | --shadowInactive arg アカウント無効までの日数を指定します。 +## | --shadowExpire arg アカウント期限満了の日付 +## | --shadowFlag arg 予約 +## | --mail arg メールアドレスを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## |[詳細] +## | 次のようなエントリを生成します。 +## | +## | dn: uid=<ユーザーID>,ou=User,<ドメインのDN> +## | objectClass: inetOrgPerson +## | objectClass: posixAccount +## | objectClass: shadowAccount +## | sn: <姓> +## | cn: <名> +## | uid: <ユーザーID> +## | uidNumber: +## | gidNumber: +## | gecos: <その他情報> +## | homeDirectory: <ホームディレクトリ> +## | loginShell: <ログインシェル> +## | userPassword: <(ハッシュ化された)ユーザーパスワード> +## | shadowLastChange: <パスワードの最終更新日> +## | shadowMin: <変更可能最短期間> +## | shadowMax: <未変更可能最長期間> +## | shadowWarning: <警告日> +## | shadowInactive: <インアクティブ> +## | shadowExpire: <失効日> +## | shadowFlag: <フラグ> +## | mail: <メールアドレス> +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +NODEFAULT=0 +P_SN= +P_CN= +P_UID= +P_UID_NUMBER= +P_GID_NUMBER= +P_GECOS= +P_HOME_DIRECTORY= +P_LOGIN_SHELL= +P_USER_PASSWORD= +P_SHADOW_LAST_CHANGE= +P_SHADOW_MIN= +P_SHADOW_MAX= +P_SHADOW_WARNING= +P_SHADOW_INACTIVE= +P_SHADOW_EXPIRE= +P_SHADOW_FLAG= +P_MAIL= + + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# 指定された UID に関する情報を /etc/passwd, /etc/shadow より抽出し、 +# 各変数にセットします。 +# ※既に値が設定されている変数にはセットしません。 +# +# @param $1 uid +# ====================================================================== +function load_default_info() +{ + P_UID=$1 + ETC_PASSWD=/etc/passwd + ETC_SHADOW=/etc/shadow + + [ "$P_UID_NUMBER" = "" ] && P_UID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $3'}` + [ "$P_GID_NUMBER" = "" ] && P_GID_NUMBER=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $4'}` + [ "$P_GECOS" = "" ] && P_GECOS=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $5'}` + [ "$P_HOME_DIRECTORY" = "" ] && P_HOME_DIRECTORY=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $6'}` + [ "$P_LOGIN_SHELL" = "" ] && P_LOGIN_SHELL=` grep -e "^${P_UID}:" ${ETC_PASSWD} | awk -F ':' {'print $7'}` + + [ "$P_USER_PASSWORD" = "" ] && P_USER_PASSWORD=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print "{CRYPT}" $2'}` + [ "$P_SHADOW_LAST_CHANGE" = "" ] && P_SHADOW_LAST_CHANGE=`grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $3'}` + [ "$P_SHADOW_MIN" = "" ] && P_SHADOW_MIN=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $4'}` + [ "$P_SHADOW_MAX" = "" ] && P_SHADOW_MAX=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $5'}` + [ "$P_SHADOW_WARNING" = "" ] && P_SHADOW_WARNING=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $6'}` + [ "$P_SHADOW_INACTIVE" = "" ] && P_SHADOW_INACTIVE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $7'}` + [ "$P_SHADOW_EXPIRE" = "" ] && P_SHADOW_EXPIRE=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $8'}` + [ "$P_SHADOW_FLAG" = "" ] && P_SHADOW_FLAG=` grep -e "^${P_UID}:" ${ETC_SHADOW} | awk -F ':' {'print $9'}` + +} + + + +# ====================================================================== +# 指定された属性を出力します。 +# 属性値が空文字の場合は、何も出力しません。 +# +# @param $1 属性 +# @param $2 属性値 +# ====================================================================== +print_attr() +{ + if [ "$2" != "" ]; then + echo "$1: $2" + fi +} + + + +# ====================================================================== +# ユーザーを登録するための ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# ====================================================================== +mkldif_for_add_user() +{ + DOMAIN_DN=$1 + + print_attr dn "uid=${P_UID},ou=User,${DOMAIN_DN}" + print_attr objectClass "inetOrgPerson" + print_attr objectClass "posixAccount" + print_attr objectClass "shadowAccount" + print_attr sn "${P_SN}" + print_attr cn "${P_CN}" + print_attr uid "${P_UID}" + print_attr uidNumber "${P_UID_NUMBER}" + print_attr gidNumber "${P_GID_NUMBER}" + print_attr gecos "${P_GECOS}" + print_attr homeDirectory "${P_HOME_DIRECTORY}" + print_attr loginShell "${P_LOGIN_SHELL}" + print_attr userPassword "${P_USER_PASSWORD}" + print_attr shadowLastChange "${P_SHADOW_LAST_CHANGE}" + print_attr shadowMin "${P_SHADOW_MIN}" + print_attr shadowMax "${P_SHADOW_MAX}" + print_attr shadowWarning "${P_SHADOW_WARNING}" + print_attr shadowInactive "${P_SHADOW_INACTIVE}" + print_attr shadowExpire "${P_SHADOW_EXPIRE}" + print_attr shadowFlag "${P_SHADOW_FLAG}" + print_attr mail "${P_MAIL}" + echo "" + +} + + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '--nodefault') NODEFAULT=1; shift 1 ;; + '--sn') P_SN="$2"; shift 2 ;; + '--cn') P_CN="$2"; shift 2 ;; + '--uidNumber') P_UID_NUMBER="$2"; shift 2 ;; + '--gidNumber') P_GID_NUMBER="$2"; shift 2 ;; + '--homeDirectory') P_HOME_DIRECTORY="$2"; shift 2 ;; + '--loginShell') P_LOGIN_SHELL="$2"; shift 2 ;; + '--userPassword') P_USER_PASSWORD="$2"; shift 2 ;; + '--shadowLastChange') P_SHADOW_LAST_CHANGE="$2"; shift 2 ;; + '--shadowMin') P_SHADOW_MIN="$2"; shift 2 ;; + '--shadowMax') P_SHADOW_MAX="$2"; shift 2 ;; + '--shadowWarning') P_SHADOW_WARNING="$2"; shift 2 ;; + '--shadowInactive') P_SHADOW_INACTIVE="$2"; shift 2 ;; + '--shadowExpire') P_SHADOW_EXPIRE="$2"; shift 2 ;; + '--shadowFlag') P_SHADOW_FLAG="$2"; shift 2 ;; + '--mail') P_LDAP_MAIL="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# デフォルト値ロード +if [ ${NODEFAULT} -eq 0 ]; then + load_default_info ${P_UID} +fi + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" +[ "${P_SN}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${P_CN}" = "" ] && read -p "CN (Common Name) > " P_CN +[ "${P_UID_NUMBER}" = "" ] && read -p "UID Number > " P_UID_NUMBER +[ "${P_GID_NUMBER}" = "" ] && read -p "GID Number > " P_GID_NUMBER +[ "${P_HOME_DIRECTORY}" = "" ] && read -p "HOME Directory > " P_HOME_DIRECTORY +[ "${P_MAIL}" = "" ] && read -p "Mail > " P_MAIL +if [ "${P_USER_PASSWORD}" = "" ]; then + confirm_password "User Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + P_USER_PASSWORD=`slappasswd -h '{CRYPT}' -c '$6$' -s ${CONFIRM_PASSWORD}` +fi + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-adduser.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-adduser.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# ユーザー登録 +# ---------------------------------------------------------------------- +echo "### --- Add User (uid=${P_UID}) ---" +mkldif_for_add_user ${DOMAIN_DN} > ${TMP_LDIF} +ldapadd -D ${ROOT_DN} -f ${TMP_LDIF} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-allclear.sh b/src/ldap-allclear.sh new file mode 100755 index 0000000..2e1890f --- /dev/null +++ b/src/ldap-allclear.sh @@ -0,0 +1,80 @@ +#!/bin/bash +######################################################################## +## Script : ldap-allclear.sh +## Name : LDAP のデータを全て削除して初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-allclear.sh [オプション] +## | +## | LDAP のデータを全て削除して、初期化します。 +## | +## |[オプション] +## | -y 問い合わせに対して全て Yes で答えます。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +NO_CONFIRM=n + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-y') NO_CONFIRM=y; shift 1 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + + + +confirm "Remove all LDAP data. Is it OK?" n +if [ $? -eq 1 ]; then + service slapd stop + rm -rf /etc/ldap/slapd.d/* + rm -rf /var/lib/ldap/* + if [ "${NO_CONFIRM}" = "y" ]; then + echo "Removed All LDAP data." + echo "Run the following command as root:" + echo "dpkg-reconfigure slapd" + echo "service slapd start" + else + dpkg-reconfigure slapd + service slapd start + fi +fi + diff --git a/src/ldap-deluser.sh b/src/ldap-deluser.sh new file mode 100755 index 0000000..f1ada82 --- /dev/null +++ b/src/ldap-deluser.sh @@ -0,0 +1,94 @@ +#!/bin/bash +######################################################################## +## Script : ldap-deluser:.sh +## Name : LDAP よりユーザーを削除します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-deluser.sh [オプション] uid +## | +## | LDAPよりユーザーを削除します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= +P_UID= + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${P_UID}" = "" ] && read -p "SN (Surname) > " P_SN +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + +# 削除 +echo "uid=${P_UID},ou=User,${DOMAIN_DN}" | ldapdelete -D ${ROOT_DN} -w ${ROOT_PW} + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} "(uid=${P_UID})" + diff --git a/src/ldap-init.sh b/src/ldap-init.sh new file mode 100755 index 0000000..7cabaff --- /dev/null +++ b/src/ldap-init.sh @@ -0,0 +1,258 @@ +#!/bin/bash +######################################################################## +## Script : ldap-init.sh +## Name : LDAP を初期化します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-init.sh [オプション] +## | +## | LDAP を初期化します。 +## | 初期化の際、ユーザー管理のための次のエントリを追加します。 +## | -Group (dn: ou=Group,) +## | -User (dn: ou=User,) +## | +## |[オプション] +## | --id arg 管理者用のIDを設定します。(デフォルト:root)) +## | --password arg 管理者用のパスワードを設定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_ID=root +ROOT_PW= +ROOT_CPW= +TMP_LDIF= + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP の設定を変更する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_change_config() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: olcDatabase={0}config,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootDN +olcRootDN: cn=${ROOT_ID},${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcSuffix +olcSuffix: ${DOMAIN_DN} + +dn: olcDatabase={1}mdb,cn=config +changeType: modify +replace: olcRootPW +olcRootPW: ${ROOT_CPW} + +EOF +} + + + +# ====================================================================== +# LDAP のルートDNを設定する ldif 形式のデータを標準出力します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +mkldif_for_add_rootdn() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + +cat << EOF +dn: cn=${ROOT_ID},${DOMAIN_DN} +objectClass: organizationalRole +objectClass: simpleSecurityObject +cn: ${ROOT_ID} +description: LDAP Administrator +userPassword: ${ROOT_CPW} + +dn: ou=Group,${DOMAIN_DN} +objectClass: organizationalUnit +ou: Group + +dn: ou=User,${DOMAIN_DN} +objectClass: organizationalUnit +ou: User + +EOF +} + + + +# ====================================================================== +# アクセス制御の設定を設定ファイルに反映します。 +# +# @param $1 ドメイン(DN形式) +# @param $2 ルートID +# @param $3 ルート暗号化済パスワード +# ====================================================================== +update_ldapconf() +{ + DOMAIN_DN=$1 + ROOT_ID=$2 + ROOT_CPW=$3 + + LDAP_CONF=/etc/ldap/ldap.conf + CONFIG_HEADER="#@ >>> ----- ACL Auto Settings -----" + CONFIG_FOOTER="#@ <<< ----- ACL Auto Settings -----" + + cp -f "${LDAP_CONF}" "${LDAP_CONF}.old" + sed -e "/${CONFIG_HEADER}/,/${CONFIG_FOOTER}/d" ${LDAP_CONF}.old > ${LDAP_CONF} + +cat << EOF >> ${LDAP_CONF} +${CONFIG_HEADER} +access to * + by self write + by dn="cn=${ROOT_ID},${DOMAIN_DN}" + +access to attr=userPassword + by self write + by dn="cn=${ROOT_ID},${ROMAIN_DN}" + by anonymous auth + by * none + +${CONFIG_FOOTER} + +EOF +} + + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + '--id') ROOT_ID="$2"; shift 2 ;; + '--password') ROOT_PW="$2"; shift 2 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + usage + exit 1 + fi + ;; + esac +done + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_ID}" = "" ] && read -p "Root ID > " ROOT_ID +if [ "${ROOT_PW}" = "" ]; then + confirm_password "Root Password > " "Re-type Password > " + if [ $? -ne 0 ]; then + echo "password verification error" + exit 1 + fi + ROOT_PW=${CONFIRM_PASSWORD} +fi + +[ "${DOMAIN}" != "" ] && DOMAIN_DN=`domainToDN ${DOMAIN}` +ROOT_CPW=`slappasswd -h '{CRYPT}' -c '$6$}' -s ${ROOT_PW}` +ROOT_DN_ORIG=`getRootDN` + + +# ---------------------------------------------------------------------- +# 一時ファイルの生成 +# ---------------------------------------------------------------------- +TMP_LDIF=$(mktemp /tmp/ldap-init.XXXXXXXXXXXX.ldif) +trap 'rm -f /tmp/ldap-init.*.ldif; exit 1' 1 2 3 15 + +# ---------------------------------------------------------------------- +# LDAP の設定を変更する。 +# ---------------------------------------------------------------------- +echo "### --- Update LDAP Config ---" +mkldif_for_change_config ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +debug_pause + +# ---------------------------------------------------------------------- +# 古い情報を削除する +# ---------------------------------------------------------------------- +echo "### --- Delete Old LDAP Informations ---" +echo "ou=Group,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "ou=User,${DOMAIN_DN}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +echo "${ROOT_DN_ORIG}" | ldapdelete -D cn=${ROOT_ID},${DOMAIN_DN} -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# ルートDNを設定する。 +# ---------------------------------------------------------------------- +echo "### --- Add LDAP Informations (Group, User) ---" +mkldif_for_add_rootdn ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} > ${TMP_LDIF} +ldapmodify -D cn=${ROOT_ID},${DOMAIN_DN} -f ${TMP_LDIF} -a -w ${ROOT_PW} +debug_pause + + +# ---------------------------------------------------------------------- +# 設定ファイルを更新する。 +# ---------------------------------------------------------------------- +echo "### --- Update /etc/ldap/ldap.conf" +update_ldapconf ${DOMAIN_DN} ${ROOT_ID} ${ROOT_CPW} +service slapd restart +debug_pause + + +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={0}config,cn=config' oldRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcRootDN +ldapsearch -Y EXTERNAL -H ldapi:/// -b "${DOMAIN_DN}" + + +rm -f /tmp/ldap-*.*.ldif + diff --git a/src/ldap-loglevel.sh b/src/ldap-loglevel.sh new file mode 100755 index 0000000..1b962d8 --- /dev/null +++ b/src/ldap-loglevel.sh @@ -0,0 +1,114 @@ +#!/bin/bash +######################################################################## +## Script : ldap-loglevel.sh +## Name : LDAP のログレベル変更スクリプト +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-loglevel.sh [オプション] [LogLevel] +## | +## | LDAP のログレベルを設定します。 +## | LogLevel の指定が無い場合、stats を設定します。 +## | LogLevel には次の Level の値または、Keyword の文字列を指定可能である。 +## | 複数指定する場合は、Level の値を OR した値を指定すれば良い。 +## | +## | Level Level(Hex) Keyword Description +## | -1 any enable all debugging +## | 0 no debugging (ログ出力なし) +## | 1 0x1 trace trace function calls +## | 2 0x2 packets debug packet handling +## | 4 0x4 args heavy trace debugging +## | 8 0x8 conns connection management +## | 16 0x10 BER print out packets sent and received +## | 32 0x20 filter search filter processing +## | 64 0x40 config configuration processing +## | 128 0x80 ACL access control list processing +## | 256 0x100 stats stats log connections/operations/results +## | 512 0x200 stats2 stats log entries sent +## | 1024 0x400 shell print communication with shell backends +## | 2048 0x800 parse print entry parsing debugging +## | 16384 0x4000 sync syncrepl consumer processing +## | 32768 0x8000 none only messages that get logged whatever log level is set +## | +## | 詳細は、https://www.openldap.org/doc/admin24/slapdconfig.html を参照のこと。 +## | +## |[オプション] +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh + + + +######################################################################## +## +## デフォルト値 +## +LOG_LEVEL=stats + + + +######################################################################## +## +## 関数群 +## + +# ====================================================================== +# LDAP のログレベルを指定されたログレベルに変更する +# ldif 形式のデータを標準出力します。 +# +# @param $1 ログレベル +# ====================================================================== +mkldif_for_change_loglevel() +{ +cat << EOF +dn: cn=config +changeType: modify +replace: olcLogLevel +olcLogLevel: ${LOG_LEVEL} +EOF +} + + +######################################################################## +## +## メイン処理 +## +for OPT in "$@"; do + case "${OPT}" in + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) + usage + exit 1 + ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + LOG_LEVEL=("$1") + shift 1 + fi + ;; + esac +done + +TMP_LDIF=$(mktemp /tmp/ldap.XXXXXXXXXXXX.ldif) +trap 'rm -f ${TMP_LDIF}; exit 1' 1 2 3 15 + +mkldif_for_change_loglevel ${LOG_LEVEL} > ${TMP_LDIF} +ldapmodify -Y EXTERNAL -H ldapi:/// -f ${TMP_LDIF} +ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn=config' cn=config + +rm -f ${TMP_LDIF} + diff --git a/src/ldap-showuser.sh b/src/ldap-showuser.sh new file mode 100755 index 0000000..b7f37d5 --- /dev/null +++ b/src/ldap-showuser.sh @@ -0,0 +1,97 @@ +#!/bin/bash +######################################################################## +## Script : ldap-showuser:.sh +## Name : LDAP に登録されているユーザーを表示します。 +## Version : 0.0.1 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +## Usage: +## |使用法) ldap-showuser.sh [オプション] uid +## | +## | LDAPに登録されているユーザーを表示します。 +## | +## |uid +## | ユーザーIDを指定します。 +## | +## |[オプション] +## | --password 管理者パスワードを指定します。 +## | -h,--help 使用法を表示します。 +## | -v,--version バージョンを表示します。 +## | +## | +## +######################################################################## +SCRIPT_FILE=${0} +SCRIPT_DIR=`dirname ${SCRIPT_FILE}` +LIB_DIR=${SCRIPT_DIR}/../lib + + + +######################################################################## +## +## ライブラリのロード +## +[ -f "${LIB_DIR}/functions.sh" ] && . ${LIB_DIR}/bash-utils.sh +[ -f "${SCRIPT_DIR}/ldap-util.sh" ] && . ${SCRIPT_DIR}/ldap-util.sh + + + +######################################################################## +## +## デフォルト値 +## +DOMAIN_DN=`getDomainDN` +ROOT_DN=`getRootDN` +ROOT_PW= + + + + +######################################################################## +## +## 関数群 +## + + + +######################################################################## +## +## メイン処理 +## + + +for OPT in "$@"; do + case "${OPT}" in + '--passwd') ROOT_PW="$2"; shift 2 ;; + '-h'|'--help') usage; exit 1 ;; + '-v'|'--version') version; exit 1 ;; + -*) usage exit 1 ;; + *) + if [[ ! -z "$1" ]] && [[ ! "$1" =~ ^-+ ]]; then + P_UID=("$1") + shift 1 + fi + ;; + esac +done + + + +# ---------------------------------------------------------------------- +# 引数整理 +# ---------------------------------------------------------------------- +[ "${ROOT_PW}" = "" ] && read -s -p "Root Password > " ROOT_PW; echo "" + + + +# ---------------------------------------------------------------------- +# 結果出力 +# ---------------------------------------------------------------------- +USER_DN="ou=User,${DOMAIN_DN}" +if [ "${P_UID}" = "" ]; then + SEARCH= +else + SEARCH="(uid=${P_UID})" +fi +ldapsearch -D ${ROOT_DN} -b ${USER_DN} -w ${ROOT_PW} ${SEARCH} + diff --git a/src/ldap-util.sh b/src/ldap-util.sh new file mode 100755 index 0000000..e36f876 --- /dev/null +++ b/src/ldap-util.sh @@ -0,0 +1,51 @@ +#!/bin/bash +######################################################################## +## Script : ldap-util.sh +## Name : LDAP 用ユーティリティ関数スクリプト +## Version : 0.0.3 +## Copyright : 2019 Nomura Kei +## License : BSD-2-Clause +######################################################################## +SCRIPT_FILE=${0} + + +######################################################################## +## +## 関数定義 +## + +# ===================================================================== +# 指定されたドメインを LDAP で利用する形式に変換します。 +# 例) ehobby.jp => dc=ehobby,dc=jp +# +# ※すでに変換済みの場合は何もしません。 +# +# @param $1 ドメイン名 +# @stdout LDAPで利用する形式 +# ===================================================================== +# +function domainToDC() { + DOMAIN=$1 + echo "${DOMAIN}" | sed -e "s/\([^\.]*\)\./dc=\1,/g" -e "s/^\(.*\),\(.*\)$/\1,dc=\2/" -e "s/dc=dc=/dc=/" +} + + +# ===================================================================== +# 登録されているドメインを出力します。 +# +# @stdout 登録されているドメイン(LDAP形式: 例:dc=ehobby,dc=jp) +# ===================================================================== +function getDomainDN() { + ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcSuffix 2> /dev/null | sed -n "s/^olcSuffix: \(.*\)/\1/p" +} + + +# ===================================================================== +# 登録されているドメインを出力します。 +# +# @stdout 登録されているドメイン(LDAP形式: 例:dc=ehobby,dc=jp) +# ===================================================================== +function getRootDN() { + ldapsearch -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcRootDN 2> /dev/null | sed -n "s/^olcRootDN: \(.*\)/\1/p" +} +