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

osTicket theme 1.6 RC4

As you already know osTicket is a support ticket system which is very easy to use and free. Developers from osTicket are back, they fixed a few bugs and cleaned a little bit most of the code.

Features:

  • Multilanguage client interface: You can add as many languages as you want for the client side.
  • Error messages can be “catched” and identified by a unique MD5 key which you can translate it in your language file.
  • You can configure the Ticket ID field to be a password field or just a text field for “security”.
  • It comes with 2 cool, light and fully XHTML valid themes which you can easily modify colors and also the HTML because of it’s clean design.
  • It has a built-in CAPTCHA module that will protect you from SPAM.
  • Search tickets based only on ticket’s subject.
  • Easy to install.
  • Last but not least, it’s 100% free, but that doesn’t mean you are allowed to remove credits πŸ˜‰

It has been tested a while now but it’s still on a beta stage, however, you might find some bugs and I’ll be happy to get some feedback from you. I didn’t include the Spanish language file this time, but I’ll do it someday πŸ™‚ If you want to translate it to other language feel free to send me your language file and I’ll include it in the next release πŸ˜‰

Here are some screenshots:

This specific version is a patched one from Nov/30/2010 which includes all the post-install instructions here, spanish translation included and all the patches needed to work with osTicket 1.6.0 (Stable), get it here: Download [download#4]

*** This is still very old news, keeping them there just for the archives ***

Are you still reading? Ok, you deserve it… Download [download#1] (Compatible with 1.6 RC5)
Necesitas el tema en espaΓ±ol? Descarga el archivo [download#2]

When you uncompress the file it will create a directory called “client”, that directory should be copied to osTicket’s root dir and the rest of the installation instructions are in the README file, have fun!

** Post install notes and bug fix:

  • The file thankyou.inc.php from this template has a code error in line 10: $ctlang->docatch($msg?) which should be changed for $ctlang->docatch($msg)?
  • Inside osTicket’s root dir, edit the index.php and comment (or delete) all the html code in order to see the template display correctly, then you just need to add this line before the footer in included: require(CLIENTINC_DIR.’main.inc.php’);. This bug and others will be fixed in the next release soon.

PHP EditDNS Updater for Linux

This is a simple PHP script which will update your dynamic DNS records using EditDNS.

Features:
– You can configure as many records as you want.
– Supports HTTP and HTTPS.
– For PHP 4x and higher compiled with sockets.
– Simple validation.

Here is the code: (editdns.php)

#!/usr/bin/php -q
<?php

$port = 443; // use 80 if you dont wanna use SSL
// add as many arrays as you want, first element is the record
// and the second is the password
// $data[] = array('myrecord1.domain.com','mypass1');
// $data[] = array('myrecord2.domain.com','mypass2');
// ... etc etc etc ;)
$data[] = array('somerecord.resolveme.com','blahblah123');
$sleep = 1; // seconds we should sleep before updating another record

// main loop
if (!is_array($data)) die("Nothing to do\n");
foreach ($data as $v) {
  echo "Updating $v[0] ... ";
  if(_send($port,"p=$v[1]&r=$v[0]")) echo "[OK]\n";
  sleep($sleep);
}

function _send($port=443,$args="") {
  if ($port == 443) $proto = "ssl";
  else $proto = "http";
  $fp = fsockopen("$proto://dyndns.editdns.net",$port,$errno,$errstr,10);
  if (!$fp) die("\nCouldn't establish connection\n");
  $out = "POST /api/dynLinux.php HTTP/1.0\r\n";
  $out .= "Host: dyndns.editdns.net\r\n";
  $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
  $out .= "Content-Length: ".strlen($args)."\r\n";
  $out .= "Connection: Close\r\n\r\n";
  $out .= $args;
  //echo $out;
  fwrite($fp, $out);
  while (!feof($fp)) {
    $res .= fgets($fp,1024);
  }
  fclose($fp);
  $parts = explode("\r\n\r\n",trim($res));
  //print_r($parts);
  // checking output
  if (preg_match("/record has been updated|record already exists/i",$parts[1])) return 1;
  // anything else should be an error
  echo "[ERROR]\n\t$parts[1]\n";
  return 0;
}

?>

Save it, chmod +x and play with it.

Old sources:
http://forums.nerdie.net/showthread.php?t=616
http://xux.in/blog/post/ip-updater-for-editdnsnet/

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";
}

?>

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";
}
?>