diff --git a/actions/add-ldap-user-to-group b/actions/add-ldap-user-to-group
deleted file mode 100755
index 7cd104ce3..000000000
--- a/actions/add-ldap-user-to-group
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/bash
-#
-# This file is part of Plinth.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-
-# Must be run as root.
-
-username="$1"
-groupname="$2"
-
-# check if group already exists
-results=$(ldapsearch -Y EXTERNAL -H ldapi:/// -b 'ou=groups,dc=thisbox' -LLL "(cn=$groupname)" cn)
-
-if [ -z "$results" ]; then
- # create group, with user as initial member
- cat <.
-#
-
-# Must be run as root.
-
-username="$1"
-
-IFS= read -r password
-if [ -z "$password" ]; then
- echo "Error: Could not read password from stdin."
- exit 2
-fi
-
-password=$(slappasswd -s "$password")
-
-cat <.
-#
-
-# Must be run as root.
-
-username="$1"
-
-IFS= read -r password
-if [ -z "$password" ]; then
- echo "Error: Could not read password from stdin."
- exit 3
-fi
-
-password=$(slappasswd -s "$password")
-
-cat <=1000) && ($3<59999) && ($3>maxuid) { maxuid=$3; } END { print maxuid+1; }')
-home_dir=/home/$username
-
-cat <.
-#
-
-# Must be run as root.
-
-username="$1"
-
-ldapdelete -Y EXTERNAL -H ldapi:/// "uid=$username,ou=users,dc=thisbox"
-
-if [ $? -eq 0 ]; then
- echo "Success: user deleted"
-else
- echo "Failed: user delete failed"
- exit 1
-fi
-
-# update groups
-results=$(ldapsearch 2>/dev/null -Y EXTERNAL -H ldapi:/// -b 'ou=groups,dc=thisbox' -LLL "(member=uid=$username,ou=users,dc=thisbox)" dn | grep -v '^$')
-
-while read -r line; do
- cat <.
-#
-
-# Must be run as root.
-
-username="$1"
-
-ldapsearch 2>/dev/null -Y EXTERNAL -H ldapi:/// -b 'ou=groups,dc=thisbox' -LLL "(member=uid=$username,ou=users,dc=thisbox)" cn | awk '/cn:/ { print $2 }'
diff --git a/actions/ldap b/actions/ldap
new file mode 100755
index 000000000..bb42c5996
--- /dev/null
+++ b/actions/ldap
@@ -0,0 +1,168 @@
+#!/bin/bash
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+# Store anything available from stdin.
+# This is used to receive passwords from Plinth.
+input="/proc/$$/fd/0"
+
+set -e # Exit on failure
+
+# XXX: ldapscripts has an issue that it can't properly extract
+# built-in templates under certain locales due to grep command
+# recognizing the source file as binary. Remove using this once the
+# bug is fixed. Passing '-a' as argument to grep seems to be a
+# solution.
+export LC_ALL=C
+
+
+create_user()
+{
+ username="$1"
+ password="$2"
+
+ # All users shall have 'users' (a group in /etc/group) as primary group.
+ ldapadduser $username users > /dev/null
+
+ set_user_password $username $password
+}
+
+
+delete_user()
+{
+ username="$1"
+
+ groups=$(get_user_groups $username)
+
+ ldapdeleteuser $username
+
+ while read -r group; do
+ ldapdeleteuserfromgroup $username $group > /dev/null || true
+ done <<< "$groups"
+}
+
+
+rename_user()
+{
+ old_username="$1"
+ new_username="$2"
+
+ groups=$(get_user_groups $old_username)
+
+ ldaprenameuser $old_username $new_username
+
+ while read -r group; do
+ ldapdeleteuserfromgroup $old_username $group > /dev/null || true
+ ldapaddusertogroup $new_username $group > /dev/null || true
+ done <<< "$groups"
+}
+
+
+set_user_password()
+{
+ username="$1"
+ password=$(slappasswd -s "$2")
+
+ # XXX: Use ldapsetpasswd as soon as ldapscripts can handle
+ # changing passwords with SASL auth EXTERNAL.
+ cat < /dev/null
+dn: uid=$username,ou=Users,dc=thisbox
+changetype: modify
+replace: userPassword
+userPassword: $password
+EOF
+}
+
+
+get_user_groups()
+{
+ # Return only supplimentary groups and don't include the 'users'
+ # primary group.
+ username="$1"
+
+ ldapid $username | cut -f 3 -d ' ' | cut -d = -f 2 | sed 's+,+\n+g' | sed "s+.*(\(.*\))+\1+" | grep -v users || true
+}
+
+
+add_user_to_group()
+{
+ username="$1"
+ groupname="$2"
+
+ # Try to create group and ignore failure if group already exists
+ ldapaddgroup $groupname > /dev/null 2>&1 || true
+
+ ldapaddusertogroup $username $groupname > /dev/null
+}
+
+
+remove_user_from_group()
+{
+ username="$1"
+ groupname="$2"
+
+ ldapdeleteuserfromgroup $username $groupname > /dev/null
+}
+
+
+setup()
+{
+ # XXX: Password setting on users is disabled as changing passwords
+ # using SASL Auth is not supported.
+ cat < /dev/null
+set /files/etc/ldapscripts/ldapscripts.conf/SERVER '"ldapi://"'
+set /files/etc/ldapscripts/ldapscripts.conf/SASLAUTH '"EXTERNAL"'
+set /files/etc/ldapscripts/ldapscripts.conf/SUFFIX '"dc=thisbox"'
+set /files/etc/ldapscripts/ldapscripts.conf/USUFFIX '"ou=Users"'
+set /files/etc/ldapscripts/ldapscripts.conf/GSUFFIX '"ou=Groups"'
+set /files/etc/ldapscripts/ldapscripts.conf/PASSWORDGEN '"true"'
+save
+EOF
+}
+
+
+setup
+
+command=$1
+shift
+case $command in
+ create-user)
+ create_user "$1" "$input"
+ ;;
+ delete-user)
+ delete_user "$@"
+ ;;
+ rename-user)
+ rename_user "$@"
+ ;;
+ set-user-password)
+ set_user_password "$1" "$input"
+ ;;
+ get-user-groups)
+ get_user_groups "$@"
+ ;;
+ add-user-to-group)
+ add_user_to_group "$@"
+ ;;
+ remove-user-from-group)
+ remove_user_from_group "$@"
+ ;;
+ *)
+ echo "Invalid sub-command"
+ exit -1
+ ;;
+esac
diff --git a/actions/remove-ldap-user-from-group b/actions/remove-ldap-user-from-group
deleted file mode 100755
index 9db407900..000000000
--- a/actions/remove-ldap-user-from-group
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/sh
-#
-# This file is part of Plinth.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-
-# Must be run as root.
-
-username="$1"
-groupname="$2"
-
-cat <.
-#
-
-# Must be run as root.
-
-old_username="$1"
-new_username="$2"
-
-cat </dev/null -Y EXTERNAL -H ldapi:/// -b 'ou=groups,dc=thisbox' -LLL "(member=uid=$old_username,ou=users,dc=thisbox)" dn | grep -v '^$')
-
-while read -r line; do
- cat <