Change cPanel’s email password through command line

This script will help you change any email’s account password without using cPanel, this is done through the command line. It was written in PHP but mostly uses shell commands so I guess it was easier to use elements from both worlds.

Use it at your own risk, this script requires to be executed as root and was done for educational purposes.

 <?php

// Inspired on	the following articles:
// https://cpanelgeek.wordpress.com/2015/08/26/resetting-email-account-password-from-command-line-in-cpanel/
// http://www.sudosu.in/2013/11/cpanel-bash-script-to-change-password_11.html

if (!isset($argv[1])) die("Usage: $argv[0] full@email [password]\n");

// generate random 8 character password
if (!isset($argv[2])) {
  $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!.-@';
  $argv[2] = substr(str_shuffle($chars),0,8);
}

// validate email contains at least a @ and break it
if (!preg_match("/\@/",$argv[1])) die("Invalid Email!\n");
list($name,$domain) = explode("@",trim($argv[1]));

// get domain owner
$user = trim(exec("/scripts/whoowns $domain"));
if (!$user) die("Invalid Domain!\n");

// encrypt password
$cpass = trim(exec("openssl passwd -1 '$argv[2]'"));
//echo "$name @ $domain with $argv[2] $cpass\n";

// get home folder
$path = trim(exec("grep \"^$user:\" /etc/passwd | cut -d\":\" -f6"));

// get shadow line and prepare it
$shadow = "$path/etc/$domain/shadow";
$tmpshadow = $shadow . ".tmp";
$rest = trim(exec("grep \"^$name:\" $shadow | cut -d\":\" -f3-"));
if (!$rest) die("Email $argv[1] does not exist!\n");

// create tmp shadow file without the user's email
exec("grep -v \"^$name:\" $shadow --------> $tmpshadow");
exec("chown $user:$user $tmpshadow");
exec("chmod 640 $tmpshadow");

// add the new user's password
exec("echo '$name:$cpass:$rest' >> $tmpshadow");

// swap shadow files and backup the old one
exec("mv $shadow $shadow".".".time());
exec("mv $tmpshadow $shadow");
echo "$argv[1] password changed to: $argv[2]\n";
?>

Save it as change_password.php and execute it to see how to use it: php change_password.php

Ensim’s (aka Parallels Pro Control Panel X for Linux) alternative ChangePasswdVirtUser

Ensim former Parallels Pro Control Panel X for Linux has a command line interface scripts as you SHOULD know 😉 which allows you to do several administrative tasks without login to the appliance. The other day I started to write an API in order to admin N Ensim servers with only 1 interface which is a lot of work/code but hell, I’ll post some screenshots later 🙂 … So one of the biggest problems I had was the script ChangePasswdVirtUser (located in /usr/local/bin), which allows you to change a virtual user’s password asking for the new password 2 times and I didn’t want to ruin my weekend and decided to hack that script and make it work like this: ChangePasswdVirtUser domain.com user newpassword

That’s so insecure! I know and I’ll come later with a more secure alternative don’t worry 😉 in the meantime you can play with it:

File: /usr/local/bin/ChangePasswdVirtUser1

#!/usr/bin/ensim-python
#
# Usage:
#
# ChangePasswdVirtUser   
#
# Example:
#
# AddVirtUser myco.com joe doe

import getopt
import getpass
import sys
import traceback
from vh3 import virthost
from vh3 import virtutil
from vh3.modules import users
import string
import be_vherrordisp

if (len(sys.argv) < 4) or (sys.argv[1] == "--help"):
    print "usage: ChangePasswdVirtUser1   "
    sys.exit(0)
else:
    # checks to see if we are in maintenance mode
    virthost.checkMaintenance()

    status = be_vherrordisp.CLIError.SUCCESS
    status_obj = be_vherrordisp.CLIError()
    options, args = getopt.getopt(sys.argv[1:],"")
    siteindex = virthost.get_site_from_anything(string.lower(args[0]))
    username = string.lower(args[1])
    passwd1 = args[2]
    if not siteindex:
        print "Domain %s does not exist on this server."% string.lower(args[0])
        sys.exit(1)
    ret = []
    try:
        virthost.edit_user(ret, siteindex, username, None, passwd1, None, None)
        status = virthost.cli_display_status_list(ret)
    except:
        status = be_vherrordisp.CLIError.ERROR
        print traceback.print_exc()
    sys.exit(status)

cpanel 535 Incorrect authentication data

I ran into a small issue when migrating some sites to a cPanel server, tried a few “tricks” (/scripts/* –force hehe) without luck till I found a great post which pointed me the solution, and it is as simple as that!

Since I’m a very lazy guy, I wrote a tiny script which does what Jerry (from cPanel forums) said/explained. Copy the code, save it and execute it. By default it won’t do anything but show the directories and files current state and how they should be. If you see something is not as it should be then you should change the $debug var to false in order to allow the script to do the job. After that everything should be fixed and if not don’t blame me, you can always do that manually 😉

#!/usr/bin/php -q
<?
// file: fix_auth_perms.php
// turn it off if you want to fix them
// based on http://forums.cpanel.net/showpost.php?p=323248&postcount=3
$debug = true;

$maps = file("/etc/domainusers");
if (!is_array($maps)) die("No users found!\n");

foreach ($maps as $map) {
  list($user,$domain) = explode(": ",trim($map));
  if (!$user || !$domain) continue;
  echo "\nChecking $domain ...\n";
  _file_fix("/home/$user/etc",$user,"mail");
  _file_fix("/home/$user/etc/$domain",$user,"mail");
  _file_fix("/home/$user/etc/$domain/shadow","","mail","0640");
  //exit;
}

// $file = full dir/file path
// $nuser = desired user name
// $ngroup = desired group name
// $perms = desired permissions in octal mode (0640)
function _file_fix($file="",$nuser="",$ngroup="",$perms="") {
  global $debug;
  $uname_array = posix_getpwuid(fileowner($file));
  $gname_array = posix_getgrgid(filegroup($file));
  $file_perms = substr(sprintf('%o', fileperms($file)), -4);
  echo "  $file owned by $uname_array[name].$gname_array[name] ($file_perms)\n";
    //wrong ownership, fixing it now!
  if (!$debug) {
    if ($nuser && $nuser != $uname_array[name]) {
      if (!chown($file, $uname_array[name])) echo "  couldn't change file owner to $nuser\n";
      else echo "  changed file owner to $nuser\n";
    }
    if ($ngroup && $ngroup != $gname_array[name]) {
      if (!chgrp($file, $gname_array[name])) echo "  couldn't change group owner to $ngroup\n";
      else echo "  changed group owner to $ngroup\n";
    }
  }
  if ($perms && $perms != $file_perms) {
    if (!$debug) {
      if (!chmod($file,octdec($perms))) echo "  couldn't change file mode to $perms\n";
      else echo "  changed file mode to $perms\n";
    }
  }
  //making a nice output :P
  if (!$nuser) $nuser = $uname_array[name];
  if (!$ngroup) $ngroup = $gname_array[name];
  if (!$perms) $perms = $file_perms;
  echo "  $file should now be owned by $nuser.$ngroup ($perms)\n";
}

?>

Install and setup Samba in Linux

What is Samba? If you don’t know what it is then you shouldn’t be reading this 😉 Samba can do a lot of things and we are only cover a basic configuration that will allow you to share specific folders on a Linux machine in the same way you share forlder in a Windows machine.

This will cover a very quick installation and setup of Samba on any Linux flavor, however in this particular case I’ll cover CentOS 5.2

First you need to install Samba’s binaries using yum 🙂 (you can use apt-get or up2date if you want)

yum install samba samba-common

Installation stage has been covered, that was fast 😉 Now we need to do a basic configuration in order to start using it and we need to design a structure… let’s say I want to setup a Linux machine to share a specific folder to everyone with read-only access and a specific folder for only local user with read/write access, so here we go:

cd /etc/samba
mv smb.conf smb.conf.backup
nano smb.conf

And paste the following configuration on the new smb.conf

[global]
netbios name = sambaserver
load printers = no
path = /home
default service = global
security = share
available = no

[share]
path = /var/ftp/pub
guest ok = yes
read only = yes
comment = Public Access
available = yes

[sambademo]
path = /home/demo
guest ok = no
writable = yes
valid users = demo
comment = User demo home
available = yes

So far we have setup a basic global configuration, a public access area and a restricted area for a local user called “demo”. Before we continue you need to make sure the folder /var/ftp/pub exists. Now, before we start our new Samba server, we need to setup the “demo” account and it can be done in 2 ways:

useradd -s /sbin/nologin demo
smbpaswd -a demo

If we don’t want to give this user shell access, or…

useradd -s /bin/bash demo
passwd demo
smbpasswd -a demo

If we want to give this user access to shell and of course we need to set the same password for the system and Samba.
It is time to start our Samba server:

/etc/init.d/smb start

Now let’s try it, on Windows do the following: Start -> Run -> cmd

net use y:\\samba_server_ip\share
net use z:\\samba_server_ip\demo /user:demo thepasswordyouset

Hopefully you will see you have 2 new units on your Windows File Explorer, Y which is a read-only folder and Z which is a read/write folder 🙂 that’s all!

If you want to do more things with Samba and you are lazy you can always get Webmin and use its module to configure Samba and use its advanced options.

NOTE: This article is for educational purposes and should be treated as it is.

Troubleshooting:

  • The network name cannot be found: Check your computer’s firewall or if your ADSL/DSL modem, sometimes by default they block all outgoing connections to Netbios port which is 139.
  • Anything else check your log files /var/log/samba/smb.log 🙂

Literature: (Thanks to them, this tutorial exists)
Sunny Walia
Joel Barrios Dueñas
Samba

Quick Ensim Backup

Nothing but an easy to use backup script for Ensim (4.X-10.X) which uses vhexport, so yeah, it’s not fast, but I wrote it because sometimes you just need to backup 1 or a few sites and drop them somewhere 😛

You just need to type this:

./backupsingle.php /path/to/backup domain1.com domain2.com ...domainN.com

And you’ll see something like this:

Building site's structure... found NN sites
Building backup for N site(s)

Starting backup for domain domain1.com (site1)... [OK]
Starting backup for domain domain2.com (site2)... [OK]
Starting backup for domain domainN.com (siteN)... [OK]

Can’t be easier 😉 copy the code, save it and chmod +x that’s all 🙂

#!/usr/bin/php -q
<?
// dirty code, no comments ;)
$vhexport = '/usr/local/bin/vhexport';
$sitelookup = '/usr/local/bin/sitelookup';

if (count($argv) <= 2) die("Usage: $argv[0] /backup/path domain1 domain2 ...domainN\n");

$path = $argv[1]; $limit = (count($argv)-1);
if (!is_dir($path)) die("$path doesn't exist, creat it first!\n");
if (preg_match("/\/$/",$path)) $path = substr($path,0,-1);

echo "Building site's structure... "; sleep(1);
$ds = explode("\n",trim(`$sitelookup -a site_handle,domain`));
if (!is_array($ds)) die("Server is empty!\n");

foreach ($ds as $dlines) {
  $tmpparts = explode(",",trim($dlines));
  if (!is_array($tmpparts)) continue;
  $domains[$tmpparts[1]] = $tmpparts[0];
}

echo "found ".count($ds)." sites\n"; sleep(1);
echo "Building backup for ".($limit-1)." site(s)\n\n";

for ($i=2;$i<=$limit;$i++) {
  $bdomain = $argv[$i];
  $bsite = $domains[$bdomain];
  if (!$bsite) { echo "Looks like $bdomain has not a valid site_handle, aborting...\n"; continue; }
  echo "Starting backup for domain $bdomain ($bsite)... ";
  $cmd = $vhexport . ' -s ' . $bsite . ' -U "file://' . $path . '/%(type)-%(name)" -z';
  //echo "\n[debug] $cmd\n";
  `$cmd`;
  echo "[OK]\n";
}
?>