123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- #!/bin/sh
- # Echo help information
- usage()
- {
- cat <<EOF
- Usage: $0 [options] <command> <parameters>
- Tool for VCS repository administration.
- VCS support: $possible_vcs
- Options:
- -h, --help
- Print help message.
- -c <PATH>, --config=<PATH>
- Specify config file (default is /etc/repoforge/rfa.conf)
- -s <git/svn>, --vcs=<git/svn>
- Choose VCS type to create new repository (default is git)
- --git
- Same as "-c git"
- --svn
- Same as "-c svn"
- Commands:
- info <repository>
- Get information for specified repository.
- add <repository1> [repository2] ...
- Create new repository.
- del <repository1> [repository2] ...
- Delete existing repository.
- fixmod <repository1> [repository2] ...
- Fix access rights for repository.
- rename <old_name> <new_name>
- Rename repository.
- useradd <repository> <r/w/rw> <user1> [user2] ...
- Set access rights for user(s) to repository.
- userdel <repository> <r/w/rw> <user1> [user2] ...
- Remove access rights for user(s) to repository.
- userdel-all <repository> <r/w/rw>
- Remove access rights for all users for repository.
- usermod <user> [<restricted|interactive>]
- Deny/permit interactive user shell (git-shell/normal shell)
- EOF
- }
- group_add()
- {
- groupadd -K GID_MIN=${group_gid_min} "${group_r_prefix}$1" || return 1
- groupadd -K GID_MIN=${group_gid_min} "${group_w_prefix}$1" || return 1
- }
- group_del()
- {
- groupdel "${group_r_prefix}$1" || return 1
- groupdel "${group_w_prefix}$1" || return 1
- }
- group_rename()
- {
- local old_name="$1"
- local new_name="$2"
- groupmod -n "${group_r_prefix}$new_name" "${group_r_prefix}$old_name" || return 1
- groupmod -n "${group_w_prefix}$new_name" "${group_w_prefix}$old_name" || return 1
- return 0
- }
- get_group_members()
- {
- local group="$1"
- grep -e "^$group:" /etc/group | sed -e "s|^.*:||" -e "s|,| |g"
- }
- create_repo_svn()
- {
- svnadmin --fs-type=fsfs create "$1" || return 1
- }
- create_repo_git()
- {
- mkdir -p "$1" || return 1
- # git -C "$1" init --bare --shared >/dev/null || return 1
- cd "$1" || return 1
- git init --bare --shared >/dev/null || return 1
- cd - >/dev/null
- }
- data_add()
- {
- local r_name="$1"
- local r_root="$2"
- local r_link="$3"
- local repo_r="${r_root}/${r_name}"
- local repo_w="${r_root}/${r_name}/${r_name}"
- mkdir -p "${repo_r}"
- local saved_umask=`umask`
- umask 002
- local create_vcs_func="create_repo_$opts_vcs"
- $create_vcs_func "$repo_w" || return 1
- umask ${saved_umask}
- }
- data_fixmod()
- {
- local r_name="$1"
- local r_root="$2"
- local r_link="$3"
- local repo_r="${r_root}/${r_name}"
- local repo_w="${r_root}/${r_name}/${r_name}"
- chmod 750 "${repo_r}" || return 1
- chgrp "${group_r_prefix}${r_name}" "${repo_r}" || return 1
- chgrp -R "${group_w_prefix}${r_name}" "${repo_w}" || return 1
- local dirs=""
- dirs=`find "$repo_w" -type d`
- local dir=""
- for dir in $dirs; do
- chmod g+s "$dir" || return 1
- done
- chmod -R g+w "${repo_w}" || return 1
- }
- data_del()
- {
- local r_name="$1"
- local r_root="$2"
- rm -Rf "$r_root/$r_name"
- }
- link_add()
- {
- local r_name="$1"
- local r_root="$2"
- local r_link="$3"
- ln -sf "$r_root/$r_name/$r_name" "$r_link/$r_name"
- }
- link_del()
- {
- local r_name="$1"
- local r_link="$2"
- rm -f "$r_link/$r_name"
- }
- repository_add()
- {
- local rep_name=""
- local repo_root
- local repo_link
- for rep_name in "$@"; do
- repo_root=`find_repo_root "$rep_name"`
- repo_link=`find_repo_link "$rep_name"`
- test "x$repo_root" = "x" || { echo "Error: The repository \"$rep_name\" already exists." 1>&2; return 1; }
- eval repo_root="\$repository_${opts_vcs}_root"
- eval repo_link="\$repository_${opts_vcs}_link"
- test "x$repo_root" = "x" && { echo "Error: Illegal repository root \"\"" 1>&2; return 1; }
- test "x$repo_link" = "x" && { echo "Error: Illegal repository link \"\"" 1>&2; return 1; }
- test -d "$repo_root" || { echo "Error: Illegal repository root \"$repo_root\"" 1>&2; return 1; }
- test -d "$repo_link" || { echo "Error: Illegal repository link \"$repo_link\"" 1>&2; return 1; }
- group_add "$rep_name" || { echo "Error: Can't add group for repository \"$rep_name\"" 1>&2; return 1; }
- data_add "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't add repository \"$rep_name\"" 1>&2; return 1; }
- data_fixmod "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't fix mode for repository \"$rep_name\"" 1>&2; return 1; }
- link_add "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't add link for repository \"$rep_name\"" 1>&2; return 1; }
- echo "Info: The repository \"$rep_name\" was succesfully created."
- done
- }
- # Delete the repository
- repository_del()
- {
- local rep_name=""
- local sure=""
- local repo_root
- local repo_link
- for rep_name in "$@"; do
- repo_root=`find_repo_root "$rep_name"`
- repo_link=`find_repo_link "$rep_name"`
- test "x$repo_root" = "x" -o "x$repo_link" = "x" && { echo "Error: Can't find repository \"$rep_name\"" 1>&2; return 1; }
- if test "x$opts_force" = "x"; then
- read -r -p "Deleting repository \"$rep_name\". Are you sure (y/n)? " sure
- test "x$sure" = "xy" -o "x$sure" = "xY" || { echo "Info: The repository \"$rep_name\" will be not deleted."; continue; }
- fi
- link_del "$rep_name" "$repo_link" || { echo "Error: Can't remove link for repository \"$rep_name\"" 1>&2; return 1; }
- data_del "$rep_name" "$repo_root" || { echo "Error: Can't remove repository \"$rep_name\"" 1>&2; return 1; }
- group_del "$rep_name" || { echo "Error: Can't remove group for repository \"$rep_name\"" 1>&2; return 1; }
- echo "Info: The repository \"$rep_name\" was succesfully deleted."
- done
- }
- # Fix broken repository: symlink, access rights, owner.
- repository_fixmod()
- {
- local rep_name=""
- local repo_root
- local repo_link
- for rep_name in "$@"; do
- repo_root=`find_repo_root "$rep_name"`
- repo_link=`find_repo_link "$rep_name"`
- test "x$repo_root" = "x" -o "x$repo_link" = "x" && { echo "Error: Can't find repository \"$rep_name\"" 1>&2; return 1; }
- data_fixmod "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't fix repository's \"$rep_name\" mode" 1>&2; return 1; }
- link_add "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't create link for repository \"$rep_name\"" 1>&2; return 1; }
- echo "Info: The repository \"$rep_name\" was succesfully fixed."
- done
- }
- # Rename existing repository
- repository_rename()
- {
- local old_name="$1"
- local new_name="$2"
- local repo_root
- local repo_link
- # Check if target name is already exists
- repo_root=`find_repo_root "$new_name"`
- test "x$repo_root" = "x" || { echo "Error: The repository \"$new_name\" is already exist" 1>&2; return 1; }
- repo_root=`find_repo_root "$old_name"`
- repo_link=`find_repo_link "$old_name"`
- test "x$repo_root" != "x" -a -d "$repo_root/$old_name" || { echo "Error: Can't find repository \"$old_name\"" 1>&2; return 1; }
- test "x$repo_root" != "x" -a -L "$repo_link/$old_name" || { echo "Error: Can't find link of repository \"$old_name\"" 1>&2; return 1; }
- # Real move repository and link
- mv -f "$repo_root/$old_name/$old_name" "$repo_root/$old_name/$new_name" || { echo "Error: Can't move repository \"$old_name\"" 1>&2; return 1; }
- mv -f "$repo_root/$old_name" "$repo_root/$new_name" || { echo "Error: Can't move repository \"$old_name\"" 1>&2; return 1; }
- link_del "$old_name" "$repo_link" || { echo "Error: Can't remove link for repository \"$old_name\"" 1>&2; }
- link_add "$new_name" "$repo_root" "$repo_link" || { echo "Error: Can't create link for repository \"$new_name\"" 1>&2; }
- # Rename a groups
- group_rename "$old_name" "$new_name" || { echo "Error: Can't rename access groups for repository \"$new_name\"" 1>&2; }
- echo "Info: The repository \"$old_name\" was succesfully renamed to \"$new_name\""
- return 0
- }
- # Show repository info
- repository_info()
- {
- local repo="$1"
- local repo_root
- local repo_link
- repo_root=`find_repo_root "$repo"`
- repo_link=`find_repo_link "$repo"`
- test "x$repo_root" != "x" -a -d "$repo_root/$repo" || { echo "Error: Can't find repository \"$repo\"" 1>&2; return 1; }
- echo "Name: $repo"
- echo "VCS : "`find_repo_vcs "$repo"`
- echo "Path: $repo_root"
- echo "Link: $repo_link"
- echo "Write access: "`get_group_members "${group_w_prefix}$repo"`
- echo "Read access: "`get_group_members "${group_r_prefix}$repo"`
- return 0
- }
- # user restricted mode
- user_getshell()
- {
- local sh=`cat /etc/passwd | grep "^$1:" | cut -d ':' -f 7`
- echo $sh
- }
- user_interactive()
- {
- local user="$1"
- local git_shell="/home/$user/git-shell-commands"
- if [ ! -f "$git_shell/no-interactive-login" ]; then
- return 0
- fi
- local sh=`cat "$git_shell/no-interactive-login" | sed -e 's/^#[ \t]*//g'`
- if [ "x$sh" = "x" ]; then
- echo "Can not get user shell, using /bin/bash..." 1>&2
- sh="/bin/bash"
- fi
- chsh -s "$sh" "$1" || return 1
- rm -f "$git_shell/no-interactive-login" || return 1
- rmdir "$git_shell" >/dev/null 2>&1
- return 0
- }
- user_restricted()
- {
- local user="$1"
- local git_shell="/home/$user/git-shell-commands"
- if [ -f "$git_shell/no-interactive-login" ]; then
- return 0
- fi
- local sh=`user_getshell "$user"`
- if [ "x$sh" = "x" ]; then
- echo "Can not get user shell, using /bin/bash..." 1>&2
- sh="/bin/bash"
- fi
- chsh -s $(command -v git-shell) "$user" || return 1
- test -d "$git_shell" || mkdir "$git_shell"
- echo "# $sh" > "$git_shell/no-interactive-login" && chmod +x "$git_shell/no-interactive-login" && return 0
- return 1
- }
- user_showmod()
- {
- local user="$1"
- local git_shell="/home/$user/git-shell-commands"
- if [ -f "$git_shell/no-interactive-login" ]; then
- echo "restricted"
- else
- echo "interactive"
- fi
- }
- user_mod()
- {
- local user="$1"
- local mode="$2"
- if ! grep -q "^$user:" /etc/passwd; then
- echo "No such user." 1>&2
- return 1
- fi
- if test "x$mode" = "x"; then
- user_showmod "$user"
- return 0
- fi
- case "$mode" in
- restricted)
- if ! user_restricted "$user"; then
- echo "Error: can not set mode, rollback..." 1>&2
- user_interactive "$user"
- return 1
- fi
- ;;
- interactive)
- if ! user_interactive "$user"; then
- echo "Error: can not set mode, rollback..." 1>&2
- user_restricted "$user"
- return 1
- fi
- ;;
- *)
- echo "Error: Illegal mode \"$mode\" (restricted|interactive)" 1>&2
- return 1
- ;;
- esac
- return 0
- }
- # Add users to access groups
- user_add()
- {
- local w=0
- local r=0
- local repository_name="$1"
- local user_name=""
- shift
- case "$1" in
- r)
- r=1
- ;;
- w)
- w=1
- ;;
- rw|wr)
- r=1
- w=1
- ;;
- *)
- echo "Error: Illegal parameter \"$1\"" 1>&2
- return 1
- ;;
- esac
- shift
- for user_name in "$@"; do
- test $r -ne 0 && adduser "${user_name}" "${group_r_prefix}${repository_name}"
- test $w -ne 0 && adduser "${user_name}" "${group_w_prefix}${repository_name}"
- done
- }
- # Remove users from access groups
- user_del()
- {
- local w=0
- local r=0
- local repository_name=$1
- local user_name=""
- shift
- case "$1" in
- r)
- r=1
- ;;
- w)
- w=1
- ;;
- rw|wr)
- r=1
- w=1
- ;;
- *)
- echo "Error: Illegal parameter \"$1\"" 1>&2
- return 1
- ;;
- esac
- shift
- for user_name in "$@"; do
- test $r -ne 0 && deluser "${user_name}" "${group_r_prefix}${repository_name}"
- test $w -ne 0 && deluser "${user_name}" "${group_w_prefix}${repository_name}"
- done
- }
- # Remove all users from access groups
- user_del_all()
- {
- local w=0
- local r=0
- local repository_name=$1
- local user_name=""
- shift
- case "$1" in
- r)
- r=1
- ;;
- w)
- w=1
- ;;
- rw|wr)
- r=1
- w=1
- ;;
- *)
- echo "Error: Illegal parameter \"$1\"" 1>&2
- return 1
- ;;
- esac
- if test $r -ne 0; then
- user_name=`get_group_members "${group_r_prefix}${repository_name}"`
- test "x$user_name" != "x" && user_del "$repository_name" "r" $user_name
- fi
- if test $w -ne 0; then
- user_name=`get_group_members "${group_w_prefix}${repository_name}"`
- test "x$user_name" != "x" && user_del "$repository_name" "w" $user_name
- fi
- }
- # Find repository VCS
- find_repo_vcs()
- {
- local r=""
- local r_root=""
- for r in $possible_vcs; do
- eval r_root="\$repository_${r}_root"
- test "x$r_root" = "x" && continue
- test -d "$r_root/$1" || continue
- echo "$r"
- break
- done
- return 0
- }
- # Find repository root path by repository name
- find_repo_root()
- {
- local r=""
- local r_root=""
- r=`find_repo_vcs "$1"`
- eval r_root="\$repository_${r}_root"
- echo "$r_root"
- }
- # Find repository link path by repository name
- find_repo_link()
- {
- local r=""
- local r_link=""
- r=`find_repo_vcs "$1"`
- eval r_link="\$repository_${r}_link"
- echo "$r_link"
- }
- #------------------ MAIN -----------------------------------------
- possible_vcs="svn git"
- # Defaults for rfa.conf
- group_gid_min="3000"
- group_w_prefix="vcs-w-"
- group_r_prefix="vcs-r-"
- repository_root=
- repository_link=
- default_vcs="git"
- # Parse command line options
- action="help"
- opts_force=""
- opts_conf="/etc/repoforge/rfa.conf"
- opts_vcs="$default_vcs"
- while test "x$1" != "x"; do
- option="$1"
- case "$option" in
- -h|--help)
- usage
- exit 0
- ;;
- -f|--force)
- opts_force=1
- ;;
- # Config file
- -c)
- shift
- opts_conf="$1"
- ;;
- --config=*)
- opts_conf=`echo "$option" | sed 's/--config=//'`
- ;;
- # Choose VCS
- -s)
- shift
- opts_vcs="$1"
- ;;
- --vcs=*)
- opts_vcs=`echo "$option" | sed 's/--vcs=//'`
- ;;
- --git)
- opts_vcs="git"
- ;;
- --svn)
- opts_vcs="svn"
- ;;
- # Default
- *)
- action="$option"
- shift
- break
- ;;
- esac
- shift
- done
- # Early help message
- test "x$action" = "xhelp" && { usage; exit 0; }
- # Check options
- bad_vcs=1
- for v in $possible_vcs; do
- test "x$opts_vcs" = "x$v" && { bad_vcs=""; break; }
- done
- test "x$bad_vcs" = "x" || { echo "Error: Illegal VCS \"$opts_vcs\"" 1>&2; exit 1; }
- # Include config file
- test -r "$opts_conf" && . $opts_conf
- # Compatibility (suppose SVN)
- test "x$repository_svn_root" = "x" && repository_svn_root="$repository_root"
- test "x$repository_svn_link" = "x" && repository_svn_link="$repository_link"
- # Action
- case "$action" in
- "info")
- test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
- repository_info "$@" || exit 1
- ;;
- "add")
- test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
- repository_add "$@" || exit 1
- ;;
- "del")
- test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
- repository_del "$@" || exit 1
- ;;
- "fixmod")
- test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
- repository_fixmod "$@" || exit 1
- ;;
- "rename")
- test $# -lt 2 && { echo "Error: The old and new repository names are expected" 1>&2; exit 1; }
- repository_rename "$@" || exit 1
- ;;
- "adduser"|"useradd")
- test $# -lt 3 && { echo "Error: Not enough parameters" 1>&2; exit 1; }
- user_add "$@" || exit 1
- ;;
- "deluser"|"userdel")
- test $# -lt 3 && { echo "Error: Not enough parameters" 1>&2; exit 1; }
- user_del "$@" || exit 1
- ;;
- "deluser-all"|"userdel-all")
- test $# -lt 2 && { echo "Error: Not enough parameters" 1>&2; exit 1; }
- user_del_all "$@" || exit 1
- ;;
- "usermod")
- test $# -lt 1 && { echo "Error: Not enough parameters" 1>&2; exit 1; }
- user_mod "$@" || exit 1
- ;;
- *)
- echo "Error: Unknown command" 1>&2
- exit 1
- ;;
- esac
- exit $?
|