From a1cba070d82a058688dea82cead1685ab6f1b9d9 Mon Sep 17 00:00:00 2001 From: Bradford Morgan White Date: Sun, 8 Feb 2026 13:03:05 -0500 Subject: [PATCH] pushing old code --- README.md | 9 ++ bin/wpm.sh | 261 +++++++++++++++++++++++++++++++++++++++++ etc/changelog.txt | 108 +++++++++++++++++ etc/wpm.conf | 39 ++++++ lib/fixserial.sh | 24 ++++ lib/wpm-backup.sh | 141 ++++++++++++++++++++++ lib/wpm-copy.sh | 96 +++++++++++++++ lib/wpm-delete.sh | 69 +++++++++++ lib/wpm-find.sh | 37 ++++++ lib/wpm-install.sh | 164 ++++++++++++++++++++++++++ lib/wpm-mangle.sh | 44 +++++++ lib/wpm-password.sh | 87 ++++++++++++++ lib/wpm-permissions.sh | 82 +++++++++++++ lib/wpm-rename.sh | 98 ++++++++++++++++ lib/wpm-settings.sh | 33 ++++++ lib/wpm-update.sh | 109 +++++++++++++++++ lib/wpm-verify.sh | 112 ++++++++++++++++++ 17 files changed, 1513 insertions(+) create mode 100644 README.md create mode 100755 bin/wpm.sh create mode 100644 etc/changelog.txt create mode 100644 etc/wpm.conf create mode 100755 lib/fixserial.sh create mode 100644 lib/wpm-backup.sh create mode 100644 lib/wpm-copy.sh create mode 100644 lib/wpm-delete.sh create mode 100644 lib/wpm-find.sh create mode 100644 lib/wpm-install.sh create mode 100644 lib/wpm-mangle.sh create mode 100644 lib/wpm-password.sh create mode 100644 lib/wpm-permissions.sh create mode 100644 lib/wpm-rename.sh create mode 100644 lib/wpm-settings.sh create mode 100644 lib/wpm-update.sh create mode 100644 lib/wpm-verify.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a3c320 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# wpm + +### the wordpress mangler + +WPM started as a rather simple script. I was working the night shift at a managed web host, and I was rather sick of installing WordPress for customers and making one-off backups of those installations when customers inevitably requested something stupid. I did what any good and proper lazy engineer would do, and I automated both processes. + +This eventually evolved to handle more and more stuff like remembering/setting permissions, renaming WordPress installations, and so on. + +This isn't currently maintained, but if people want it updated or something, let me know. I could be encouraged to take it up again. diff --git a/bin/wpm.sh b/bin/wpm.sh new file mode 100755 index 0000000..47b3497 --- /dev/null +++ b/bin/wpm.sh @@ -0,0 +1,261 @@ +#!/bin/bash +. /usr/local/etc/wpm/wpm.conf +. /usr/local/lib/wpm-backup.sh +. /usr/local/lib/wpm-copy.sh +. /usr/local/lib/wpm-delete.sh +. /usr/local/lib/wpm-find.sh +. /usr/local/lib/wpm-install.sh +. /usr/local/lib/wpm-mangle.sh +. /usr/local/lib/wpm-password.sh +. /usr/local/lib/wpm-permissions.sh +. /usr/local/lib/wpm-rename.sh +. /usr/local/lib/wpm-settings.sh +. /usr/local/lib/wpm-update.sh +. /usr/local/lib/wpm-verify.sh + +############################ +# TRY BLOCK IMPLEMENTATION # +# SCRIPT HALTS ON FAILURE # +############################ + +scream() { echo "$0: $*" >&2 | tee -a $LOGFILE; } +die() { scream "$*"; exit 1; } +try() { "$@" || die "cannot $*"; } + +############################# +# MAKE SURE LOG FILE EXISTS # +############################# + +([ -e $LOGFILE ] || try touch $LOGFILE ) && try chmod 660 $LOGFILE + +################################# +# MAKE SURE THAT TEMPDIR EXISTS # +################################# + +[ -d $TEMPDIR ] || try mkdir -m 770 -p $TEMPDIR; +[ -d $TEMPDIR ] || echo "$TEMPDIR does not exist" +[ -d $TEMPDIR ] || exit 1 + +######################################## +# MAKE SURE THAT THE BACKUPPATH EXISTS # +######################################## + +if [ "$BACKUPPATH" != "PARENTOFGIVEN" ]; then + [ -d $BACKUPPATH ] || try mkdir -m 770 -p $BACKUPPATH + [ -d $BACKUPPATH ] || echo "$BACKUPPATH does not exist" + [ -d $BACKUPPATH ] || exit 1 +fi + +#################################### +# SET THE REFERENCE ID FOR LOGGING # +#################################### + +INSTANCEID=`openssl rand -hex 5` + +########################################### +# IF USER VARIABLES ARE NOT SET IN CONFIG # +########################################### + +if [ -z $SELECTED_GROUP ]; then + NGINX=`ps -ef | grep nginx | grep -v root | grep -v grep | awk '{print $1}' | sort | uniq` + HTTPD=`ps -ef | grep httpd | grep -v root | grep -v grep | grep -v tomcat | awk '{print $1}' | sort | uniq` + APACHE=`ps -ef | grep apache | grep -v root | grep -v grep | grep -v tomcat | awk '{print $1}' | sort | uniq` + [[ -z $NGINX ]] || SELECTED_GROUP=`id -g $NGINX` + [[ -z $HTTPD ]] || SELECTED_GROUP=`id -g $HTTPD` + [[ -z $APACHE ]] || SELECTED_GROUP=`id -g $APACHE` + [ -z $SELECTED_GROUP ] && echo "no selected group found, please set it in /usr/local/etc/wpm/wpm.conf" +fi + +###################### +# THE USAGE FUNCTION # +###################### + +function usage() { + printf "wpm version ${WPMVERSION}\n\n" + + case "$1" in + -r|--rename) + printf " -r | --rename \n" + printf "\t %-21s \t %s \n" "-o | --oldname" "old domain name to be abandoned" + printf "\t %-21s \t %s \n" "-n | --newname" "new domain name to be in use" + printf "\t %-21s \t %s \n\n" "-p | --path" "location of installation" + + echo "This function will change the domain name of WordPress installation." + echo "If you provide no path, it will default to your current directory." + echo "Example: wpm -r -o foo.com -n bar.com -p /var/www/example" + echo "Example: wpm -r -o foo.com -n bar.com" + ;; + + -c|--copy) + printf " -c | --copy \n" + printf "\t %-21s \t %s \n" "-o | --oldname" "original domain name" + printf "\t %-21s \t %s \n" "-n | --newname" "new domain name" + printf "\t %-21s \t %s \n" "-s | --source" "location of original installation" + printf "\t %-21s \t %s \n\n" "-d | --destination" "location for copy" + + echo "This will duplicate a WordPress installation and assign it a provided domain name." + echo "Example: wpm -c -o foo.com -n bar.com -s /var/www/foo -d /var/www/bar" + ;; + + -i|--install) + printf " -i | --install \n" + printf "\t %-21s \t %s \n" "-d | --domain" "domain name to be used" + printf "\t %-21s \t %s \n" "-s | --skip-ftp" "skip ftpsockets config and permissions" + printf "\t %-21s \t %s \n\n" "-p | --path" "location for installation" + + echo "This will install WordPress at the desired location." + echo "If no path is provided it will default to current directory." + echo "Example: wpm -i -d foo.com -p /var/www/foo" + echo "Example: wpm -i -d foo.com" + ;; + + -u|--update) + printf " -u | --update \n" + printf "\t %-21s \t %s \n" "-b | --backup" "do a backup first" + printf "\t %-21s \t %s \n" "-g | --plugins" "update plugins too" + printf "\t %-21s \t %s \n" "-s | --skip-ftp" "skip ftpsockets permissions" + printf "\t %-21s \t %s \n\n" "-p | --path" "location of the WP install" + + echo "This just runs an update to current on WordPress." + echo "If no path is given, it will try the current directory." + echo "Example: wpm -u -p /var/www/foo" + ;; + + -p|--permissions) + printf " -p | --permissions \n\n" + + echo "This will attempt to set \"sane\" permissions on a WordPress installation." + echo "It will make a backup of permissions if getfacl is installed." + echo "If no path is provided, it will attempt to use the current directory." + echo "Example: wpm -p /var/www/foo" + ;; + + -d|--delete) + printf " -d | --delete \n" + printf "\t %-21s \t %s \n" "-b | --backup" "do a backup first" + printf "\t %-21s \t %s \n\n" "-p | --path" "installation to be deleted" + + echo "This will delete a WordPress installation, and optionally back it up first." + echo "Example: wpm -d -p /var/www/foo" + ;; + + -b|--backup) + printf " -b | --backup\t backup a wordpress installation \n" + printf "\t %-21s \t %s \n" "-n | --no-compress" "the xz or gz container won't actually be compressed" + printf "\t %-21s \t %s \n" "-d | --delete-old" "delete older backups" + printf "\t %-21s \t %s \n" "-s | --skip-uploads" "skip the uploads directory" + printf "\t %-21s \t %s \n\n" "-p | --path" "the WordPress install's location" + + echo "This will create a compressed tarball of the installation, including DB" + echo "If no path is provided, it will default to the current directory." + echo "Example: wpm -b -p /var/www/foo -n -d -s" + echo "Example: wpm -b" + ;; + + -w|--password) + printf " -w | --password \n" + printf "\t %-21s \t %s \n" "-d | --duration" "duration of password change" + printf "\t %-21s \t %s \n" "-u | --username" "user who's password should be changed" + printf "\t %-21s \t %s \n" "-v | --view" "view available WP usernames" + printf "\t %-21s \t %s \n\n" "-p | --path" "location of the WP install" + + echo "This will change the current password of a user." + echo "A duration of 0 can be used for permanent changed, and the default is 10 minutes." + echo "If no path is provided, it will attempt to use the current directory." + echo "Example: wpm -w -u admin -p /var/www/foo" + ;; + -e|--settings) + printf " --settings \n\n" + + echo "This allows you to view or change wpm settings." + echo "Example: wpm --settings list" + echo "Example: wpm --settings BACKUPPATH=\"PARENTOFGIVEN\"" + echo "Example: wpm --settings LOGFILE=\"/home/admin/wpm.log\" BACKUPPATH=\"/home/admin/wpm_backups\"" + ;; + + -s|--search) + printf " -s | --search \n\n" + + echo "This will attempt to find WordPress installations." + echo "If no search path is provided, it will use /" + echo "Example: wpm --search /var/www" + ;; + + -m|--mangle) + printf " -m | --mangle \n" + printf "\t %-21s \t %s \n" "-n | --no-backup" "do not backup the WP installs first (bad idea, btw)" + printf "\t %-21s \t %s \n" "-p | --path" "the search path for installs" + printf "\t %-21s \t %s \n\n" "-s | --skip-search" "skip doing the search for installs" + + echo "This will attempt to find WordPress installations and then update them." + echo "If you have recently run wpm -s you can skip rerunning it here with -s." + echo "If no search path is provided, it will use /" + echo "Example: wpm -m -p /var/www" + ;; + + -v|--verify) + printf " -v | --verify \n" + printf "\t %-21s \t %s \n" "-s | --scan" "scan with maldet" + printf "\t %-21s \t %s \n" "-m | --md5" "md5 present files against those from wordpress.org" + printf "\t %-21s \t %s \n" "-b | --backup" "run a backup first" + printf "\t %-21s \t %s \n" "-r | --replace" "replace modified files (requires --md5)" + printf "\t %-21s \t %s \n\n" "-p | --path" "location of the WP install" + + echo "This will attempt to detect and optionally remove malware, and/or replace files that are corrupt." + echo "If no path is given it will attempt to use the current directory." + echo "If you do not choose md5 or scan, it does nothing." + echo "Example: wpm -v -m -s -b -r -p /var/www/foo" + ;; + + -h|--help) + printf "\n\n%b%s%b\n\n" "$RED" "Please tell me that you do not actually need help for help..." "$DEFAULT" + ;; + esac + + if [ -z $1 ]; then + printf "%b%s \t %b%s%b\n" "$RED" "-r" "$CIAN" "rename a wordpress installation" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-c" "$CIAN" "copy a wordpress installation" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-i" "$CIAN" "install wordpress" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-u" "$CIAN" "update a wordpress installation" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-p" "$CIAN" "attempt to set sane permissions on a WP installation" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-d" "$CIAN" "delete a wordpress installation" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-b" "$CIAN" "backup a wordpress installation" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-w" "$CIAN" "change a wordpress user's password" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-e" "$CIAN" "change wpm settings" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-s" "$CIAN" "search for wordpress installations" "$DEFAULT" + printf "%b%s \t %b%s%b\n" "$RED" "-m" "$CIAN" "find and update wordpress installations" "$DEFAULT" + printf "%b%s \t %b%s%b\n\n" "$RED" "-v" "$CIAN" "verify a wordpress installation" "$DEFAULT" + fi + +} # END USAGE + + +################# +# LET'S DO THIS # +################# + +case "$1" in + -r|--rename) rename "${@:2}" ;; + -c|--copy) copy "${@:2}" ;; + -i|--install) install "${@:2}" ;; + -u|--update) update "${@:2}" ;; + -p|--permissions) permissions "${@:2}" ;; + -d|--delete) delete "${@:2}" ;; + -b|--backup) backup "${@:2}" ;; + -w|--password) password "${@:2}" ;; + -e|--settings) settings "${@:2}" ;; + -s|--search) search "${@:2}" ;; + -m|--mangle) mangle "${@:2}" ;; + -v|--verify) verify "${@:2}" ;; + -h|--help) usage "${@:2}" ;; + *) + if [ "$1" == "" ]; then + usage + else + echo "$1 not implemented" + exit 1 + fi + ;; +esac + +# EOF diff --git a/etc/changelog.txt b/etc/changelog.txt new file mode 100644 index 0000000..2b5503f --- /dev/null +++ b/etc/changelog.txt @@ -0,0 +1,108 @@ +############## +# CHANGE LOG # +############## + +4.1.1 -- fixed a bug in wpm-verify's maldet integration + +4.1.0 -- cleaned up code style + fixed bugs in backup: + backup does not skip uploads when asked + backup creates tar bomb + backup cannot compress if low RAM + variable names are more understandable + log output and stdout are now the same text + output is a bit more verbose + the usage function is now per-function help, cuz there's too much output + the md5 option of verify will now attempt to NOT override wp-config.php + settings function can now be invoked with -e + added --skip-ftp option to install & update + removed perl updater script, now uses bash in wpm-update.sh + rename no longer tries to modify any file with oldname match + rename attempts to set HOME and SITEURL + colorful output added in some places + +4.0.2 -- fixed bugs with duration in password function + fixed orphaned WP install message + fixed SQL syntax error in -w -v + changed to Absurd License 2 + +4.0.1 -- fixed a bug in backups that was preventing compression despite flag + fixed a bug in maldet detection for verify + added "PARENTOFGIVEN" as an option for backup location + +4.0.0 -- added proper option flags + changed behavior of temp password function to add support for permanent + added view option to temp password (list users) + added parameter order independence + configuration options moved to config file + made temp directory configurable + removed need for rpl + added make file for installation + added default for current directory on some options + makefile for installation + SSH option removed due to issues with php's libssh2 + added the settings function + changed default files permissions + added the find function + added the mangle function + update will now optionally update plugins + wpm.sh was way too long, split it into many files + $r is now declared globally so that logs are easier to follow + the idea being that when one function calls another you + know that it was all part of one invocation + fixserial.php is now fixserial.sh + added verify + refactored many different sections + changed to ISC license + +3.1.0 -- added rename + added housekeeping + changed changedomain to copy + changed htaccess detection method + changed from wp to wpm + backup now accepts an argument to remove old backups + backup now accepts an argument to circumvent compression + backup will now use gz if xz is not present + added delete + updated fixerial.php for php7 + +3.0.0 -- added SSH options + added try/scream/die + moved wordpress download into getwp + moved UID/GID detection into getwwwid + +2.1.0 -- fixed numerous bugs + added pv check on backup + removed sql file compression since it will be compressed with archive + +2.0.0 -- added temppass + added htaccess detection mechanisms + fixed a bug: backups not receiving file names on some systems + logging includes more than installs! + fixed bug in freespace check for backup + backup now tells you if it fails freespace check + +1.2.0 -- backups have timestamps + changed compression mechanisms to xz + fixed an ssl bug on wp download + added more error checking on all the things + if pv isn't present tar will use -v + +1.1 -- added help + +1.0 -- added permissions + +0.9 -- added update + +0.8 -- added install + +0.7 -- added error checking + added fixserial + added a check for db existence b4 executing + +0.6 -- added check for free space + +0.5 -- no longer assumes that you are backing up your cwd + forces you to pass the directory to be backed up + +0.1 -- created wp (wordpress backup script) diff --git a/etc/wpm.conf b/etc/wpm.conf new file mode 100644 index 0000000..ee25a42 --- /dev/null +++ b/etc/wpm.conf @@ -0,0 +1,39 @@ +# WPM CONFIG + +# you can bump this to skip a version in the future when I add updating +WPMVERSION="4.1.1" + +# this is the user from whom a uid will be copied +# if unset, the uid of 9001 will be used +SELECTED_USER="" + +# this is the gid that will be used, if unset +# the program will try and copy the gid of nginx/apache +SELECTED_GROUP="" + +# this is the location at which backups will be created +# if you want the backup path to be the parent of the document root then +# you can set this to PARENTOFGIVEN +BACKUPPATH="/var/www/backup" + +# this is the location of the log file +LOGFILE="/var/log/wpm.log" + +# this is our temp directory +TEMPDIR="/tmp" + +# OOOH PRETTY COLORS! +BLACK="\033[38;5;0m" +RED="\033[38;5;1m" +GREEN="\033[38;5;2m" +BROWN="\033[38;5;94m" +BLUE="\033[38;5;4m" +PURPLE="\033[38;5;93m" +CIAN="\033[38;5;6m" +LIGHTGREY="\033[38;5;246m" +DARKGREY="\033[38;5;240m" +YELLOW="\033[38;5;220m" +PINK="\033[38;5;5m" +WHITE="\033[38;5;15m" +ORANGE="\033[38;5;208m" +DEFAULT="\033[39m" diff --git a/lib/fixserial.sh b/lib/fixserial.sh new file mode 100755 index 0000000..a9c5d83 --- /dev/null +++ b/lib/fixserial.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +POSIT=() +while [[ $# -gt 0 ]] +do + key="$1" + case $key in + -f|--file) FILE=$2; shift;; + -n|--new) NEW=$2; shift;; + -o|--old) OLD=$2; shift;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift +done +set -- "${POSIT[@]}" + +if [ -z $FILE ] || [ -z $NEW ] || [ -z $OLD ]; then + echo "You must provide a file, a new domain, and an old domain" + exit 1 +fi + +sed 's/;s:/;\ns:/g' $FILE | awk -F'"' '/s:.+'$OLD'/ {sub("'$OLD'", "'$NEW'"); n=length($2)-1; sub(/:[[:digit:]]+:/, ":" n ":")} 1' | sed ':a;N;$!ba;s/;\ns:/;s:/g' | sed "s/$OLD/$NEW/g" > ${FILE}.tmp + +mv ${FILE}.tmp ${FILE} diff --git a/lib/wpm-backup.sh b/lib/wpm-backup.sh new file mode 100644 index 0000000..48263d7 --- /dev/null +++ b/lib/wpm-backup.sh @@ -0,0 +1,141 @@ +####################### +# THE BACKUP FUNCTION # +####################### + +function backup() { + + POSIT=() + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -n|--no-compress) NOCOMPRESS="yes" ;; + -d|--delete-old) DELETEOLD="yes" ;; + -s|--skip-uploads) SKIPUPLOADS="yes" ;; + -p|--path) DESTDIR="$2" ; shift ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}" + + DELETEOLD="${DELETEOLD:-no}" + SKIPUPLOADS="${SKIPUPLOADS:-no}" + DESTDIR="${DESTDIR:-`pwd`}" + + [ -f ${DESTDIR}/wp-config.php ] || echo "this isn't a wordpress installation" + [ -f ${DESTDIR}/wp-config.php ] || exit 1 + + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM BACKUP CALLED ON $DATETIME WITH VERSION $WPMVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing backup on $DESTDIR" >> $LOGFILE + + cd $DESTDIR + + local NAME=`echo $DESTDIR | rev | cut -d '/' -f 1 | rev` + + if [ "$NAME" == "" ] || [ ${#NAME} -lt 3 ] || [ "$NAME" == "html" ]; then + NAME=`hostname -f` + fi + + echo "==$INSTANCEID==The name is ${NAME}" | tee -a $LOGFILE + + local DBNAME=`grep DB_NAME wp-config.php | awk -F "'" '{print $4}'` + echo "==$INSTANCEID==The DB name is ${DBNAME}" | tee -a $LOGFILE + + if mysql "${DBNAME}" >/dev/null 2>&1 $TEMPDIR/${DBNAME}.${DATETIME}.sql + echo "==$INSTANCEID==The database dump is complete." | tee -a $LOGFILE + + if [ "$BACKUPPATH" == "PARENTOFGIVEN" ]; then + BACKUPPATH=`dirname $DESTDIR` + DELETEOLD="no" + fi + + if [ "$DELETEOLD" == "yes" ]; then + try find $BACKUPPATH -mtime +1 -type f -exec rm -fv '{}' \;; + echo "==$INSTANCEID==removed old backups" | tee -a $LOGFILE; + fi + + if [[ "${SKIPUPLOADS}" == "no" ]]; then + local SF=`echo $(($(stat -f --format="%a*%S" .)))`; + local SN=`du -sb .|awk '{print $1}'`; + local SB=${SN} + local SN=`echo $(($SN + $SN))`; + if [ $SF -gt $SN ]; then + echo "==$INSTANCEID==Adequate free space detected" | tee -a $LOGFILE + else + echo "==$INSTANCEID==Insufficient space available. Terminating" | tee -a $LOGFILE + exit 1 + fi + fi + + echo "==$INSTANCEID==Starting archive creation" | tee -a $LOGFILE + + [ `which xz` ] && COMPRESSOR="xz" + [ `which pv` ] && PROGRESS="pv" + + if [ "$PROGRESS" == "pv" ]; then + TAROPTIONS="cf" + INTERPRED="pv -per -s${SB} |" + else + TAROPTIONS="cfv" + INTERPRED="" + fi + + if [ "$SKIPUPLOADS" == "yes" ]; then + EXCLUDES="--exclude-tag=tagfile --exclude-vcs --exclude-backups" + else + EXCLUDES="--exclude-vcs --exclude-backups" + fi + + if [ -d $DESTDIR/wp-content/uploads ]; then + touch $DESTDIR/wp-content/uploads/tagfile + fi + + MEMORY=$( echo $((`cat /proc/meminfo | grep MemTotal | awk '{print $2}'`/1024)) ) + if [[ $MEMORY -lt 1152 ]]; then + NOCOMPRESS="yes" + else + NOCOMPRESS="${NOCOMPRESS:-no}" + fi + + if [ "$NOCOMPRESS" == "yes" ]; then + if [ "$COMPRESSOR" == "xz" ]; then + PRED="xz -0 > $BACKUPPATH/$NAME.$DATETIME.tar.xz" + else + PRED="gzip -1 > $BACKUPPATH/$NAME.$DATETIME.tar.gz" + fi + else + if [ "$COMPRESSOR" == "xz" ]; then + PRED="xz -9 > $BACKUPPATH/$NAME.$DATETIME.tar.xz" + else + PRED="gzip -9 > $BACKUPPATH/$NAME.$DATETIME.tar.gz" + fi + fi + + [ `which getfacl` ] && getfacl -R `pwd` > .permissions_backup.${DATETIME} + [ `which getfacl` ] && echo "==$INSTANCEID==Permissions backup completed." | tee -a $LOGFILE + [ `which getfacl` ] && echo "==$INSTANCEID==Restore with setfacl --restore=${DESTDIR}/.permissions_backup.${DATETIME}" | tee -a $LOGFILE + + CMD="try tar $TAROPTIONS - $EXCLUDES --transform=\"flags=r;s|^|$DATETIME/|\" --show-transformed * $TEMPDIR/$DBNAME.$DATETIME.sql | $INTERPRED $PRED" + + eval $CMD + + rm -f $TEMPDIR/$DBNAME.$DATETIME.sql + + if [ -f $DESTDIR/wp-content/uploads/tagfile ]; then + rm -f $DESTDIR/wp-content/uploads/tagfile + fi + + echo "==$INSTANCEID==The archive is available at $BACKUPPATH/$NAME.$DATETIME.tar.xz" + +} # END BACKUP diff --git a/lib/wpm-copy.sh b/lib/wpm-copy.sh new file mode 100644 index 0000000..ea68725 --- /dev/null +++ b/lib/wpm-copy.sh @@ -0,0 +1,96 @@ +##################### +# THE COPY FUNCTION # +##################### + +function copy() { + + POSIT=() + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -o|--oldname) OLDNAME=$2; shift;; + -n|--newname) NEWNAME=$2; shift;; + -s|--source) SOURCE=$2; shift;; + -d|--destination) DESTDIR=$2; shift ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}" + + [ -d $SOURCE ] || echo "source directory does not exist" + [ -d $SOURCE ] || exit 1 + + [ -f $SOURCE/wp-config.php ] || echo "this isn't a wordpress installation" + [ -f $SOURCE/wp-config.php ] || exit 1 + + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM COPY CALLED ON $DATETIME WITH VERSION $WPVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing copy from $SOURCE to $DESTDIR" | tee -a $LOGFILE + + [ -d $DESTDIR ] || try mkdir -p $DESTDIR + try rsync -aq $SOURCE/* $DESTDIR + echo "==$INSTANCEID==File copy complete." | tee -a $LOGFILE + + cd $DESTDIR + + local DBNAME=`grep DB_NAME wp-config.php | awk -F "'" '{print $4}'` + local DBUSER=`grep DB_USER wp-config.php | awk -F "'" '{print $4}'` + + echo "==$INSTANCEID==Database $DBNAME with user $DBUSER." | tee -a $LOGFILE + if mysql "${DBNAME}" >/dev/null 2>&1 $TEMPDIR/$DBNAME.sql + echo "==$INSTANCEID==DB dump to SQL file is complete." | tee -a $LOGFILE + + echo "==$INSTANCEID==Changing $SOURCE to $DESTDIR with sed" | tee -a $LOGFILE + try find `pwd` -type f -exec sed -i "s/$SOURCE/$DESTDIR/g" '{}' \; + try sed -i "s|$SOURCE|$DESTDIR|g" $TEMPDIR/$DBNAME.sql + echo "==$INSTANCEID==Sed complete." | tee -a $LOGFILE + + echo "==$INSTANCEID==Running fixserial on $TEMPDIR/$DBNAME.sql" | tee -a $LOGFILE + try /usr/local/lib/fixserial.sh -o $OLDNAME -n $NEWNAME -f $TEMPDIR/$DBNAME.sql + echo "==$INSTANCEID==Fixserial has been run." | tee -a $LOGFILE + + [ -e "$SOURCE/.htaccess" ] && cp -v $SOURCE/.htaccess $DESTDIR/.htaccess + [ -d "$SOURCE/.ssh" ] && cp -vR $SOURCE/.ssh $DESTDIR/ + [ -e "$SOURCE/wp-content/uploads/.htaccess" ] && cp -v $SOURCE/wp-content/uploads/.htaccess $DESTDIR/wp-content/uploads/.htaccess + echo "==$INSTANCEID==Dot files copied (if they existed)." | tee -a $LOGFILE + + local NEWDB=${DBNAME} + NEWDB+=`openssl rand -hex 2` + echo "==$INSTANCEID==New database name is ${NEWDB}" | tee -a $LOGFILE + + if mysql "${NEWDB}" >/dev/null 2>&1 > $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" >> $LOGFILE + echo "=$INSTANCEID=Executing delete on $DIRECTORY" >> $LOGFILE + + if [ "$DOBACKUP" == "yes" ];then + backup -p `pwd` + else + echo "==$INSTANCEID==WARNING: BACKUP HAS BEEN DECLINED!" | tee -a $LOGFILE + fi + + cd $DIRECTORY + + local DBNAME=`grep DB_NAME wp-config.php | cut -f 2 -d ' ' | awk -F "'" '{print $2}'` + echo "==$INSTANCEID==The DB name is $DBNAME" | tee -a $LOGFILE + + local DBUSER=`grep DB_USER wp-config.php | cut -f 2 -d ' ' | awk -F "'" '{print $2}'` + echo "==$INSTANCEID==The DB user is $DBUSER" | tee -a $LOGFILE + + if mysql "${DBNAME}" >/dev/null 2>&1 > $TEMPDIR/orphans.list + fi + done + + if [ -s $TEMPDIR/orphans.list ]; then + echo "==$INSTANCEID==Orphaned WordPress installs found:" | tee -a $LOGFILE + cat $TEMPDIR/orphans.list | sed "s/^/==$INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Orphans are in $TEMPDIR/orphans.list" | tee -a $LOGFILE + else + echo "==$INSTANCEID==No orphaned WordPress installs found." | tee -a $LOGFILE + fi + + echo "==$INSTANCEID==Results are in $TEMPDIR/wordpress_installs.list" | tee -a $LOGFILE + echo "==$INSTANCEID==Search is complete." | tee -a $LOGFILE + +} # END SEARCH diff --git a/lib/wpm-install.sh b/lib/wpm-install.sh new file mode 100644 index 0000000..a5a9a5f --- /dev/null +++ b/lib/wpm-install.sh @@ -0,0 +1,164 @@ +######################## +# THE INSTALL FUNCTION # +######################## + +function install() { + POSIT=(); + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -d|--domain) DOMAIN="$2"; shift ;; + -p|--path) DESTDIR="$2"; shift ;; + -s|--skip-ftp) SKIPFTP="yes" ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}" + + DESTDIR="${DESTDIR:-`pwd`}" + SKIPFTP="${SKIPFTP:-no}" + local DATETIME=`date +%Y%m%d.%H%M` + + [ -z $DOMAIN ] && echo "you must provide a domain name" + [ -z $DOMAIN ] && exit 1 + + [ -f "$DESTDIR/wp-config.php" ] && echo "this is already a wordpress installation" + [ -f "$DESTDIR/wp-config.php" ] && exit 1 + + [ -d "$DESTDIR/wp-content" ] && echo "this is already a wordpress installation" + [ -d "$DESTDIR/wp-content" ] && exit 1 + + echo "==WP INSTALL CALLED ON $DATETIME WITH VERSION $WPVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==starting install in $DESTDIR==" | tee -a $LOGFILE + + cd $DESTDIR + + local PASSWORD=`openssl rand -hex 5` + local TRIMMEDDOMAIN=`echo $DOMAIN | sed -e 's/\.//g' | tr '-' '_'| cut -c -10` + local TRIMMEDDOMAIN+=`openssl rand -hex 2` + echo "==$INSTANCEID==Password and seed have been generated" | tee -a $LOGFILE + + echo "==$INSTANCEID==Checking $TEMPDIR/wp-installer" | tee -a $LOGFILE + [ -d $TEMPDIR/wp-installer ] || try mkdir -p $TEMPDIR/wp-installer + try chmod 1777 $TEMPDIR/wp-installer + + echo "==$INSTANCEID==Removing old versions if they exist" | tee -a $LOGFILE + try find $TEMPDIR/wp-installer/ -mtime +1 -iname "wordpress.latest*" -delete + + if [ -e $TEMPDIR/wp-installer/wordpress.latest.tar ]; then + echo "==$INSTANCEID==Recent version already present" | tee -a $LOGFILE + else + try wget -O $TEMPDIR/wp-installer/wordpress.latest.tar.gz https://wordpress.org/latest.tar.gz --no-check-certificate &> /dev/null + try gunzip $TEMPDIR/wp-installer/wordpress.latest.tar.gz &> /dev/null + if [ -e $TEMPDIR/wp-installer/wordpress.latest.tar ]; then + try touch $TEMPDIR/wp-installer/wordpress.latest.tar + else + echo "==$INSTANCEID==tar ball of wp not present?!" | tee -a $LOGFILE + exit 1 + fi + echo "==$INSTANCEID==Recent version downloaded" | tee -a $LOGFILE + fi + + if [ ! -e $TEMPDIR/wp-installer/wordpress.latest.tar ]; then + echo "==$INSTANCEID==Cannot get archive at $TEMPDIR/wp-installer/" | tee -a $LOGFILE + exit 1 + fi + + echo "==$INSTANCEID==Extracting Wordpress in $DESTDIR" | tee -a $LOGFILE + + if tar -f $TEMPDIR/wp-installer/wordpress.latest.tar -x --strip-components=1; then + echo "==$INSTANCEID==Extracting Wordpress in $DESTDIR complete" | tee -a $LOGFILE + else + echo "==$INSTANCEID==Extracting Wordpress in $INSTANCEID failed, trying with legacy tar options" | tee -a $LOGFILE + if tar -f $TEMPDIR/wp-installer/wordpress.latest.tar -x --strip-path=1; then + echo "==$INSTANCEID==Extracting Wordpress in $DESTDIR complete" | tee -a $LOGFILE + else + echo "==$INSTANCEID==Extracting Wordpress completely failed in $DESTDIR" | tee -a $LOGFILE + exit 1 + fi + fi + + echo "==$INSTANCEID==Generating configuration" | tee -a $LOGFILE + + echo -e " wp-config.php + + try wget -O - -q https://api.wordpress.org/secret-key/1.1/salt/ >> wp-config.php + if [[ "$SKIPFTP" == "no" ]]; then + echo "==$INSTANCEID==Adding ftp user $TRIMMEDDOMAIN==" | tee -a $LOGFILE + [ -z $SELECTED_USER ] && USERID="9001" || USERID=`id -n $SELECTED_USER` + # THE UIDS WE KNOW WE SHOULDNT BE USING + local BADNESS=("0" "2" "3" "4" "5" "6" "7" "8" "9" "10" "13" "34" "38" "39" "41" "65534" "100") + for BADDY in ${BADNESS[*]}; do + if [ $USERID -eq $BADDY ]; then + echo "UID of $BADDY is not allowed setting to over nine thousand" + USERID="9001" + fi + done # END BADNESS CHECK + try useradd $TRIMMEDDOMAIN -u $USERID -g $SELECTED_GROUP -d $DESTDIR -s /bin/sh -p $(openssl passwd -1 $PASSWORD) -o + echo "==$INSTANCEID==FTP user added" | tee -a $LOGFILE + echo "define('FS_METHOD', 'ftpsockets');" >> wp-config.php + echo "define('FTP_USER', '$TRIMMEDDOMAIN');" >> wp-config.php + echo "define('FTP_PASS', '$PASSWORD');" >> wp-config.php + echo "define('FTP_HOST', '127.0.0.1');" >> wp-config.php + echo "==$INSTANCEID==FTP details and FS_METHOD added to config" | tee -a $LOGFILE + elif [[ "$SKIPFTP" == "yes" ]]; then + echo "==$INSTANCEID==Skipping FTP per user request." | tee -a $LOGFILE + fi + + echo -e "\$table_prefix = 'wp_';\n\ndefine ('WPLANG', '');\ndefine('WP_DEBUG', false);\nif ( ! defined('ABSPATH') )\ndefine('ABSPATH', dirname(__FILE__) . '/');\nrequire_once(ABSPATH . 'wp-settings.php');" >> wp-config.php + + local DATABASES=`mysql -e "show databases like '$TRIMMEDDOMAIN'" | wc -l` + if [ "$DATABASES" -lt 1 ]; then + echo "==$INSTANCEID==Creating database $TRIMMEDDOMAIN" | tee -a $LOGFILE + echo "create database $TRIMMEDDOMAIN" | mysql + echo "==$INSTANCEID==Granting permissions on $TRIMMEDDOMAIN to $TRIMMEDDOMAIN@localhost" | tee -a $LOGFILE + echo "grant all on $TRIMMEDDOMAIN.* to '$TRIMMEDDOMAIN'@'localhost' identified by '$PASSWORD'" | mysql + else + echo "==$INSTANCEID==Database $TRIMMEDDOMAIN already exists" | tee -a $LOGFILE + exit 1 + fi + + local DATABASES=`mysql -e "show databases like '$TRIMMEDDOMAIN'" | wc -l` + if [ "$DATABASES" -lt 1 ]; then + echo "==$INSTANCEID==Database creation failed. Terminating." | tee -a $LOGFILE + exit 1 + fi + + if [[ "$SKIPFTP" == "no" ]]; then + echo "==$INSTANCEID==Setting Permissions on $DESTDIR" | tee -a $LOGFILE + try mkdir $DESTDIR/wp-content/uploads + GROUP="`getent group $SELECTED_GROUP | cut -d ':' -f 1`" + echo "==$INSTANCEID==User: $TRIMMEDDOMAIN, group: $GROUP" | tee -a $LOGFILE + try chown -R $TRIMMEDDOMAIN:$GROUP $DESTDIR + try find $DESTDIR -type d -exec chmod 750 '{}' \; + try find $DESTDIR -type f -exec chmod 640 '{}' \; + [ -d $DESTDIR/wp-content/uploads ] && try chmod 770 $DESTDIR/wp-content/uploads || try install -d -m 0770 $DESTDIR/wp-content/uploads + elif [[ "$SKIPFTP" == "yes" ]]; then + echo "==$INSTANCEID==Permissions were skipped. Potentially very unsafe." | tee -a $LOGFILE + fi + + local FPMCHECK=`ps -ef | grep fpm | grep -v grep` + local APACHECHECK=`ps -ef | egrep 'apache|httpd|apache2' | grep -v egrep | grep -v grep` + if [ ${#FPMCHECK} -eq 0 ]; then + if [ ${#APACHECHECK} -gt 0 ]; then + echo "php_flag engine off" > $DESTDIR/wp-content/uploads/.htaccess + echo "==$INSTANCEID==Wrote htaccess file to uploads (mod_php style)" | tee -a $LOGFILE + echo -e "\n\nRewriteEngine On\nRewriteBase /\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule . /index.php [L]\n\n" > $DESTDIR/.htaccess + echo "==$INSTANCEID==Wrote standard WP htaccess to $DESTDIR/.htaccess" | tee -a $LOGFILE + fi + elif [ ${#FPMCHECK} -gt 0 ]; then + if [ ${#APACHECHECK} -gt 0 ]; then + echo "Options -ExecCGI" > $DESTDIR/wp-content/uploads/.htaccess + echo "==$INSTANCEID==Wrote htaccess file to uploads (fpm style)" | tee -a $LOGFILE + echo -e "\n\nRewriteEngine On\nRewriteBase /\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule . /index.php [L]\n\n" > $DESTDIR/.htaccess + echo "==$INSTANCEID==Wrote standard WP htaccess to $DESTDIR/.htaccess" | tee -a $LOGFILE + fi + else + echo "==$INSTANCEID==Apache not detected, skipping htaccess" | tee -a $LOGFILE + fi + + echo "==$INSTANCEID==Install Complete." | tee -a $LOGFILE + +} # END INSTALL diff --git a/lib/wpm-mangle.sh b/lib/wpm-mangle.sh new file mode 100644 index 0000000..35e567c --- /dev/null +++ b/lib/wpm-mangle.sh @@ -0,0 +1,44 @@ +####################### +# THE MANGLE FUNCTION # +####################### + +mangle() { + POSIT=(); + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -n|--no-backup) BACKUP="no" ;; + -p|--path) DESTDIR=$2 ; shift ;; + -s|--skip-search) SKIPSEARCH="yes" ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}"; + + SKIPSEARCH="${SKIPSEARCH:-no}" + BACKUP="${BACKUP:-yes}" + DESTDIR="${DESTDIR:-/}" + [ -d $DESTDIR ] || DESTDIR="/" + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM MANGLE CALLED ON $DATETIME WITH VERSION $WPVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing mangle on $DESTDIR" | tee -a $LOGFILE + + if [ "$SKIPSEARCH" == "yes" ]; then + [ -f $TEMPDIR/wordpress_installs.list ] || echo "==$INSTANCEID==$TEMPDIR/wordpress_installs.list not found." | tee -a $LOGFILE + exit 1 + else + search $DESTDIR + fi + + while read LINE + do + if [ "$BACKUP" == "yes" ]; then + backup --path $LINE --skip-uploads + fi + update --path $LINE --plugins + done < $TEMPDIR/wordpress_installs.list + +} # END MANGLE diff --git a/lib/wpm-password.sh b/lib/wpm-password.sh new file mode 100644 index 0000000..db422e9 --- /dev/null +++ b/lib/wpm-password.sh @@ -0,0 +1,87 @@ +######################### +# THE PASSWORD FUNCTION # +######################### + +function password() { + + while [[ $# -gt 0 ]] + do + KEY="$1" + case $KEY in + -d|--duration) DURATION=$2 ; shift ;; + -u|--username) USERNAME=$2 ; shift ;; + -v|--view) VIEW="yes" ;; + -p|--path) DIRECTORY=$2 ; shift ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + + DIRECTORY=${DIRECTORY:-`pwd`} + USERNAME=${USERNAME:-admin} + VIEW=${VIEW:-no} + DURATION=${DURATION:-600s} + + [ -f $DIRECTORY/wp-config.php ] || echo "this isn't a wordpress installation" + [ -f $DIRECTORY/wp-config.php ] || exit 1 + + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM PASSWORD CALLED ON $DATETIME WITH VERSION $WPMVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing password on $DIRECTORY" | tee -a $LOGFILE + + cd $DIRECTORY + local DATABASENAME=`grep DB_NAME wp-config.php | cut -f 2 -d ',' | cut -f 2 -d "'"` + echo "==$INSTANCEID==The DB name is $DATABASENAME" | tee -a $LOGFILE + + if mysql "${DATABASENAME}" >/dev/null 2>&1 .permissions_backup.${DATETIME} + echo "To rollback: setfacl --restore=${DESTDIR}/.permissions_backup.${DATETIME}" + fi + + echo "==WPM PERMISSIONS CALLED ON $DATETIME WITH VERSION $WPMVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing permissions on $DESTDIR" | tee -a $LOGFILE + + echo "==$INSTANCEID==Ensuring the uploads directory exists" | tee -a $LOGFILE + [ -d "$DESTDIR/wp-content/uploads" ] || mkdir -p $DESTDIR/wp-content/uploads + + echo "==$INSTANCEID==Setting file and directory permissions" | tee -a $LOGFILE + try find $DESTDIR -type d -exec chmod 750 '{}' \; + try find $DESTDIR -type f -exec chmod 640 '{}' \; + + echo "==$INSTANCEID==Setting ownership" | tee -a $LOGFILE + + [ -z $SELECTED_USER ] && UID="9001" || UID=`id -u -n $SELECTED_USER` + + # THE UIDS WE KNOW WE SHOULDNT BE USING + local BADNESS=("0" "2" "3" "4" "5" "6" "7" "8" "9" "10" "13" "34" "38" "39" "41" "65534" "100") + for BADDY in ${BADNESS[*]}; do + if [ "$UID" == "$BADDY" ]; then + echo "UID of $BADDY is not allowed setting to over nine thousand" + UID="9001" + fi + done # END BADNESS CHECK + + echo "==$INSTANCEID==User: `id -u -n $UID`, Group: `getent group $SELECTED_GROUP | cut -d: -f1`" | tee -a $LOGFILE + try chown -R `id -u -n $UID`:`getent group $SELECTED_GROUP | cut -d: -f1` $DESTDIR + + local FPMCHECK=`ps -ef | grep fpm | grep -v grep` + local APACHECHECK=`ps -ef | egrep 'apache|httpd|apache2' | grep -v egrep | grep -v grep` + + if [ ${#FPMCHECK} -eq 0 ]; then + if [ ${#APACHECHECK} -gt 0 ]; then + echo "php_flag engine off" > $DESTDIR/wp-content/uploads/.htaccess + echo "==$INSTANCEID==Wrote htaccess file to uploads (mod_php style)" | tee -a $LOGFILE + try find $DESTDIR/wp-content/uploads/ -type d -exec chmod 770 '{}' \; + echo "==$INSTANCEID==Uploads directory set 770" | tee -a $LOGFILE + fi + elif [ ${#FPMCHECK} -gt 0 ]; then + if [ ${#APACHECHECK} -gt 0 ]; then + echo "Options -ExecCGI" > $DESTDIR/wp-content/uploads/.htaccess + echo "==$INSTANCEID==Wrote htaccess file to uploads (fpm style)" | tee -a $LOGFILE + try find $DESTDIR/wp-content/uploads/ -type d -exec chmod 770 '{}' \; + echo "==$INSTANCEID==Uploads directory set 770" | tee -a $LOGFILE + fi + else + echo "==$INSTANCEID==Apache not running, no htaccess written." | tee -a $LOGFILE + fi + + echo "==$INSTANCEID==Checking special directories." | tee -a $LOGFILE + + [ -d "$DESTDIR/wp-content/cache" ] && find $DESTDIR/wp-content/cache -type d -exec chmod 770 '{}' \; + [ -d "$DESTDIR/wp-content/w3tc-config" ] && find $DESTDIR/wp-content/w3tc-config -type d -exec chmod 770 '{}' \; + [ -d "$DESTDIR/cache" ] && find $DESTDIR/cache -type d -exec chmod 770 '{}' \; + [ -d "$DESTDIR/w3tc-config" ] && find $DESTDIR/w3tc-config -type d -exec chmod 770 '{}' \; + [ -d "$DESTDIR/stats" ] && chown -R stats $DESTDIR/stats + [ -d "$DESTDIR/wp-content/wflogs" ] && find $DESTDIR/wp-content/wflogs -type d -exec chmod 770 '{}' \; + [ -d "$DESTDIR/wp-content/wfcache" ] && find $DESTDIR/wp-content/wfcache -type d -exec chmod 770 '{}' \; + [ -d "$DESTDIR/wp-content/wflogs" ] && find $DESTDIR/wp-content/wflogs -type f -exec chmod 660 '{}' \; + + echo "==$INSTANCEID==Permissions set complete." | tee -a $LOGFILE + +} # END PERMISSIONS diff --git a/lib/wpm-rename.sh b/lib/wpm-rename.sh new file mode 100644 index 0000000..e5cc746 --- /dev/null +++ b/lib/wpm-rename.sh @@ -0,0 +1,98 @@ +####################### +# THE RENAME FUNCTION # +####################### + +function rename() { + POSIT=(); + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -o|--oldname) OLDNAME=$2; shift;; + -n|--newname) NEWNAME=$2; shift;; + -p|--path) DESTDIR=$2; shift;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}" + + DESTDIR=${DESTDIR:-`pwd`} + if [ ! -d $DESTDIR ]; then + echo "$DESTDIR doesn't exist" + exit 1 + fi + + [ -f wp-config.php ] || echo "This isn't a wordpress installation." + [ -f wp-config.php ] || exit 1 + + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM RENAME CALLED ON $DATETIME WITH VERSION $WPVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing rename from $OLDNAME to $NEWNAME" | tee -a $LOGFILE + + local DBNAME=`grep DB_NAME wp-config.php | awk -F "'" '{print $4}'` + + echo "==$INSTANCEID==Database is $DBNAME" | tee -a $LOGFILE + + if mysql "${DBNAME}" >/dev/null 2>&1 ${TEMPDIR}/${DBNAME}.${DATETIME}.sql + sed -i "s/${OLDNAME}/${NEWNAME}/g" ${TEMPDIR}/${DBNAME}.${DATETIME}.sql + try /usr/local/lib/fixserial.sh -o $OLDNAME -n $NEWNAME -f ${TEMPDIR}/${DBNAME}.${DATETIME}.sql + try mysql "$DBNAME" < $TEMPDIR/${DBNAME}.${DATETIME}.sql + try rm -fv ${TEMPDIR}/${DBNAME}.${DATETIME}.sql + echo "==$INSTANCEID==DB transform complete" | tee -a $LOGFILE + + echo "==$INSTANCEID==Commencing file operations." | tee -a $LOGFILE + + try cp -v $DESTDIR/wp-config.php $DESTDIR/.wp-config.php.$DATETIME.bak + + if ! grep -q 'WP_HOME' $DESTDIR/wp-config.php; then + sed -i "s|\$table_prefix.*$|&\n define( 'WP_HOME', 'https://$NEWNAME' );|" $DESTDIR/wp-config.php + else + sed -i "s|^.*WP_HOME.*$|define( 'WP_HOME', 'https://$NEWNAME' );|" $DESTDIR/wp-config.php + fi + + if ! grep -q 'WP_SITEURL' $DESTDIR/wp-config.php; then + sed -i "s|\$table_prefix.*$|&\n define( 'WP_SITEURL', 'https://$NEWNAME' );|" $DESTDIR/wp-config.php + else + sed -i "s|^.*WP_SITEURL.*$|define( 'WP_HOME', 'https://$NEWNAME' );|" $DESTDIR/wp-config.php + fi + + WPTHEME=$(mysql -sN -e "select \`option_value\` from $DBNAME.\`wp_options\` where \`option_name\`='template';"); + + if [ -f $DESTDIR/wp-content/themes/$WPTHEME/functions.php ]; then + try cp -v $DESTDIR/wp-content/themes/$WPTHEME/functions.php $DESTDIR/wp-content/themes/$WPTHEME/.functions.php.$DATETIME.bak + sed -i "s|\<\?php$|&\n update_option( 'siteurl', 'https://$NEWNAME' );|" $DESTDIR/wp-content/themes/$WPTHEME/functions.php + sed -i "s|\<\?php$|&\n update_option( 'home', 'https://$NEWNAME' );|" $DESTDIR/wp-content/themes/$WPTHEME/functions.php + REMOVE_LINES="yes" + else + printf "%s\n%s\n%s\n%s" '' > $DESTDIR/wp-content/themes/$WPTHEME/functions.php + if [ -f $DESTDIR/wp-content/themes/$WPTHEME/functions.php ]; then + REMOVE_FILE="yes" + else + echo "==$INSTANCEID==Could not create functions.php in $DESTDIR/wp-content/themes/$WPTHEME/" | tee -a $LOGFILE + fi + fi + + wget -O/dev/null -q --no-check-certificate https://$NEWNAME; + + if [[ "$REMOVE_LINES" == "yes" ]]; then + sed -i 's/^update_option.*$//' $DESTDIR/wp-content/themes/$WPTHEME/functions.php + elif [[ "$REMOVE_FILE" == "yes" ]]; then + if [ -f $DESTDIR/wp-content/themes/$WPTHEME/functions.php ]; then + rm -f $DESTDIR/wp-content/themes/$WPTHEME/functions.php + fi + fi + + echo "==$INSTANCEID==File operations complete." | tee -a $LOGFILE + echo "==$INSTANCEID==Rename of $OLDNAME to $NEWNAME complete" | tee -a $LOGFILE + +} # END RENAME diff --git a/lib/wpm-settings.sh b/lib/wpm-settings.sh new file mode 100644 index 0000000..383e04b --- /dev/null +++ b/lib/wpm-settings.sh @@ -0,0 +1,33 @@ +######################### +# THE SETTINGS FUNCTION # +######################### + +function settings() { + + if [[ "$1" == "list" ]]; then + try egrep -v '^#.*$' /usr/local/etc/wpm/wpm.conf | egrep -v '^$' + exit 0 + fi + + [ -z "$1" ] && echo "please provide a setting" + [ -z "$1" ] && exit 1 + + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM SETTINGS CALLED ON $DATETIME WITH VERSION $WPVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing settings on /usr/local/etc/wpm/wpm.conf" | tee -a $LOGFILE + + try cp -v /usr/local/etc/wpm/wpm.conf /usr/local/etc/wpm/wpm.${DATETIME}.bak + + echo "==$INSTANCEID==Backup of wpm.conf made @ /usr/local/etc/wpm/wpm.${DATETIME}.bak" | tee -a $LOGFILE + + for VAR in "$@"; do + MATCH=`echo $VAR | awk -F '=' '{print $1}'` + echo "${VAR}" + try sed -i "s/^${MATCH}.*/${VAR}/g" /usr/local/etc/wpm/wpm.conf + done + + echo "==$INSTANCEID==Settings function complete." | tee -a $LOGFILE + +} # END SETTINGS diff --git a/lib/wpm-update.sh b/lib/wpm-update.sh new file mode 100644 index 0000000..d31ddc0 --- /dev/null +++ b/lib/wpm-update.sh @@ -0,0 +1,109 @@ +####################### +# THE UPDATE FUNCTION # +####################### + +function update() { + POSIT=(); + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -b|--backup) BACKUP="yes" ;; + -g|--plugins) PLUGINS="yes" ;; + -s|--skip-ftp) SKIPFTP="yes" ;; + -p|--path) DESTDIR=$2 ; shift ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}"; + + BACKUP="${BACKUP:-no}" + PLUGINS="${PLUGINS:-no}" + DESTDIR="${DESTDIR:-`pwd`}" + SKIPFTP="${SKIPFTP:-no}" + + [ -d $DESTDIR ] || exit 1 + cd $DESTDIR + if [ "${BACKUP}" == "yes" ]; then + backup --path $DESTDIR --skip-uploads + fi + + [ -f wp-config.php ] || echo "this isn't a wordpress installation" + [ -f wp-config.php ] || exit 1 + + local DATETIME=`date +%Y%m%d.%H%M` + + echo "==WPM UPDATE CALLED ON $DATETIME WITH VERSION $WPMVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + echo "==$INSTANCEID==Executing update on $DESTDIR" | tee -a $LOGFILE + + echo "==$INSTANCEID==Checking $TEMPDIR/wp-installer" | tee -a $LOGFILE + + [ -d $TEMPDIR/wp-installer ] || mkdir -p $TEMPDIR/wp-installer + + echo "==$INSTANCEID==Removing old versions" | tee -a $LOGFILE + find $TEMPDIR/wp-installer/ -mtime +1 -name wordpress.latest.tar -exec rm -fv '{}' \; + + if [ -e $TEMPDIR/wp-installer/wordpress.latest.tar ]; then + echo "==$INSTANCEID==Recent version already present" | tee -a $LOGFILE + else + try wget -O $TEMPDIR/wp-installer/wordpress.latest.tar.gz https://wordpress.org/latest.tar.gz --no-check-certificate &> /dev/null + try touch $TEMPDIR/wp-installer/wordpress.latest.tar.gz + try gunzip $TEMPDIR/wp-installer/wordpress.latest.tar.gz &> /dev/null + echo "==$INSTANCEID==Recent version downloaded" | tee -a $LOGFILE + fi + + if [ ! -e $TEMPDIR/wp-installer/wordpress.latest.tar ]; then + echo "==$INSTANCEID==Cannot get archive at $TEMPDIR/wp-installer/" | tee -a $LOGFILE + exit 1 + fi + + if tar -f $TEMPDIR/wp-installer/wordpress.latest.tar -x --strip-components=1; then + echo "==$INSTANCEID==Extracting Wordpress in $DESTDIR complete" | tee -a $LOGFILE + else + echo "==$INSTANCEID==Extracting Wordpress in $DESTDIR failed, trying with legacy tar options" | tee -a $LOGFILE + if tar -f $TEMPDIR/wp-installer/wordpress.latest.tar -x --strip-path=1; then + echo "==$INSTANCEID==Extracting Wordpress in $DESTDIR complete" | tee -a $LOGFILE + else + echo "==$INSTANCEID==Extracting Wordpress completely failed in $DESTDIR" | tee -a $LOGFILE + exit 1 + fi + fi + + if [ "${PLUGINS}" == "yes" ]; then + + PLUGINLIST=$(find wp-content/plugins/ -maxdepth 1 -type d | sed 's#wp-content/plugins/##') + for PLUGINNAME in $PLUGINLIST; do + curl -L -k -s http://api.wordpress.org/plugins/info/1.0/$PLUGINNAME.xml | grep download_link | cut -c40- | sed s/\].*// >> $TEMPDIR/plugin_update.list + done + for FILE in $(cat $TEMPDIR/plugin_update.list); do + curl -L -k -s -o $TEMPDIR/tmp.zip $FILE + unzip -qq -o $TEMPDIR/tmp.zip -d wp-content/plugins/ + rm /tmp/tmp.zip + done + rm -f $TEMPDIR/plugin_update.list + + THEMELIST=$(find wp-content/themes/ -maxdepth 1 -type d | sed 's#wp-content/themes/##') + for THEMENAME in $THEMELIST; do + THEMENAMELENGTH=$(echo $THEMENAME | wc -c) + THEMENAMELENGTH=$(($THEMENAMELENGTH-1)) + curl -L -k -s -d 'action=theme_information&request=O:8:"stdClass":1:{s:4:"slug";s:'$THEMENAMELENGTH':"'$THEMENAME'";}' http://api.wordpress.org/themes/info/1.0/ |sed -n 's|.*http\(.*\)zip.*|http\1zip\n|p' >> $TEMPDIR/theme_update.list + done + for FILE in $(cat $TEMPDIR/theme_update.list); do + curl -L -k -s -o $TEMPDIR/tmp.zip $FILE + unzip -qq -o $TEMPDIR/tmp.zip -d wp-content/themes/ + rm $TEMPDIR/tmp.zip + done + + fi + + if [[ "$SKIPFTP" == "no" ]]; then + echo "==$INSTANCEID==Running permissions" | tee -a $LOGFILE + permissions $DESTDIR + elif [[ "$SKIPFTP" == "yes" ]]; then + echo "==$INSTANCEID==Permission setting skipped." | tee -a $LOGFILE + fi + + echo "==$INSTANCEID==Update complete" | tee -a $LOGFILE + +} # END UPDATE diff --git a/lib/wpm-verify.sh b/lib/wpm-verify.sh new file mode 100644 index 0000000..2043cd4 --- /dev/null +++ b/lib/wpm-verify.sh @@ -0,0 +1,112 @@ +############## +# WPM VERIFY # +############## + +function verify() { + POSIT=(); + while [[ $# -gt 0 ]]; do + KEY="$1" + case $KEY in + -s|--scan) SCAN="yes" ;; + -m|--md5) HASH="yes" ;; + -b|--backup) BACKUP="yes" ;; + -r|--replace) REPLACE="yes" ;; + -p|--path) DESTDIR="$2" ; shift ;; + *) echo "$1 not implemented" ; POSIT+=("$1") ;; + esac + shift + done + set -- "${POSIT[@]}"; + + SCAN="${SCAN:-no}" + HASH="${HASH:-no}" + BACKUP="${BACKUP:-no}" + REPLACE="${REPLACE:-no}" + DESTDIR="${DESTDIR:-`pwd`}" + local DATETIME=`date +%Y%m%d.%H%M` + + [ -d $DESTDIR ] || echo "directory $DIR does not exist" + [ -d $DESTDIR ] || exit 1 + cd $DESTDIR + + [ -f wp-config.php ] || echo "this isn't a wordpress installation" + [ -f wp-config.php ] || exit 1 + + echo "==WPM VERIFY CALLED ON $DATETIME WITH VERSION $WPMVERSION==" | tee -a $LOGFILE + echo "==UNIQUE IDENTIFIER $INSTANCEID==" | tee -a $LOGFILE + + echo "==$INSTANCEID==Executing verify on $DESTDIR" | tee -a $LOGFILE + + if [ "$BACKUP" == "yes" ]; then + backup -p $DESTDIR -s + fi + + ################## + # MD5 COMPARISON # + ################## + if [ "$HASH" == "yes" ]; then + # FIRST, GET THE LOCALLY INSTALLED VERSION + local VERSION=`grep '$wp_version =' $DESTDIR/wp-includes/version.php | cut -f 2 -d '=' | cut -f 2 -d "'"` + [ -z $VERSION ] && echo "Could not determine the WP version" + [ -z $VERSION ] && exit 1 + + echo "==$INSTANCEID==Hash called on WP version $VERSION" | tee -a $LOGFILE + + # MAKE OUR DIRECTORY FOR WORK + try mkdir -p $TEMPDIR/verify/$VERSION + + # GET THE VERSION FROM WP + try wget -O $TEMPDIR/verify/wordpress.$VERSION.tgz https://wordpress.org/wordpress-$VERSION.tar.gz --no-check-certificate &> /dev/null + echo "==$INSTANCEID==Successfully got $TEMPDIR/verify/wordpress.$VERSION.tgz" | tee -a $LOGFILE + + # LET'S EXTRACT IT + try tar -xzf $TEMPDIR/verify/wordpress.$VERSION.tgz -C $TEMPDIR/verify/$VERSION/ + + # MD5 THE VERSION FROM WP + find $TEMPDIR/verify/$VERSION/wordpress/ -type f -exec md5sum {} \; > $TEMPDIR/verify/$VERSION/record.lst + + # MD5 THE VERSION CURRENTLY INSTALLED + find . -type f -exec md5sum {} \; > $TEMPDIR/verify/$VERSION/installed.lst + + while read LINE; do + RECORD_FIELD_1=`echo $line | cut -f 1 -d ' '` + RECORD_FIELD_2=`echo $line | cut -f 2 -d ' '` + WP_FILE=`echo $RECORD_FIELD_2 | rev | cut -d '/' -f 1 | rev` + INSTALLED_FIELD_1=`grep "$WP_FILE" $TEMPDIR/verify/$VERSION/installed.lst | cut -f 1 -d ' '` + INSTALLED_FIELD_2=`grep "$WP_FILE" $TEMPDIR/verify/$VERSION/installed.lst | cut -f 2 -d ' '` + if [ "$RECORD_FIELD_1" != "$INSTALLED_FIELD_1" ]; then + echo "==$INSTANCEID==$WP_FILE DIFFERENCE DETECTED!" | tee -a $LOGFILE + echo "==$INSTANCEID==DEBUG OUTPUT: record $RECORD_FIELD_2; installed $INSTALLED_FIELD_2" | tee -a $LOGFILE + echo "==$INSTANCEID==DEBUG OUTPUT: md5 record $RECORD_FIELD_1; md5 installed $INSTALLED_FIELD_1" | tee -a $LOGFILE + if [ "$REPLACE" == "yes" ] && [[ ! "${INSTALLED_FIELD_2}" != *"wp-config.php"* ]]; then + try cp $RECORD_FIELD_2 ./$INSTALLED_FIELD_2 + echo "==$INSTANCEID==$RECORD_FIELD_2 replaced $INSTALLED_FIELD_2" | tee -a $LOGFILE + fi + fi + done <$TEMPDIR/verify/$VERSION/record.lst + rm -rf $TEMPDIR/verify/$VERSION + fi # END IF HASH + + ################## + # VIRUS SCANNING # + ################## + if [ "$SCAN" == "yes" ]; then + if maldet 1>/dev/null; then + try maldet -u + echo "==$INSTANCEID==Maldet DB updated" | tee -a $LOGFILE + if [ "$REPLACE" == "yes" ]; then + maldet --config-option scan_clamscan=1,quarantine_hits=1 + echo "==$INSTANCEID==Maldet config with quarantine" | tee -a $LOGFILE + else + maldet --config-option scan_clamscan=1,quarantine_hits=0 + echo "==$INSTANCEID==Maldet config without quarantine" | tee -a $LOGFILE + fi # END IF REPLACE + maldet -a $DESTDIR + echo "==$INSTANCEID==Maldet run on $DESTDIR" | tee -a $LOGFILE + else + echo "==$INSTANCEID==Maldet could not run, because not installed" | tee -a $LOGFILE + fi # END IF MALDET + fi # END IF SCAN + + echo "==$INSTANCEID==Verify complete at `date +%Y%m%d.%H%M`" | tee -a $LOGFILE +}