#!/usr/bin/php
<?php
/*
  vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4:
  Codificación: UTF-8
  +----------------------------------------------------------------------+
  | Elastix version 2.0                                                  |
  | http://www.elastix.org                                               |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006 Palosanto Solutions S. A.                         |
  +----------------------------------------------------------------------+
  | Cdla. Nueva Kennedy Calle E 222 y 9na. Este                          |
  | Telfs. 2283-268, 2294-440, 2284-356                                  |
  | Guayaquil - Ecuador                                                  |
  | http://www.palosanto.com                                             |
  +----------------------------------------------------------------------+
  | The contents of this file are subject to the General Public License  |
  | (GPL) Version 2 (the "License"); you may not use this file except in |
  | compliance with the License. You may obtain a copy of the License at |
  | http://www.opensource.org/licenses/gpl-license.php                   |
  |                                                                      |
  | Software distributed under the License is distributed on an "AS IS"  |
  | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See  |
  | the License for the specific language governing rights and           |
  | limitations under the License.                                       |
  +----------------------------------------------------------------------+
  | The Original Code is: Elastix Open Source.                           |
  | The Initial Developer of the Original Code is PaloSanto Solutions    |
  +----------------------------------------------------------------------+
  $Id: elastix-admin-passwords.php,v 1.1 2007/01/09 23:49:36 alex Exp $
*/
require_once 'Console/Getopt.php';

$g_mysql_running = FALSE;

define('BACKTITLE', 'Elastix password configuration');
define('PASSWD_PATH', '/etc/elastix.conf');
define('REGEXP_VALID_PASSWORD', '/^([a-zA-Z0-9 .@=_!-]+)$/');

// Parse command-line options
$opt = Console_Getopt::getopt($argv, '', array(
    'init',     // prepare passwords for first-time use
    'change',   // change existing set of passwords
));
if (PEAR::isError($opt)) error_exit($opt->getMessage()."\n");
//validateOptions($opt);
foreach ($opt[0] as $option) switch ($option[0]) {
case '--init':
    exit(action_initPasswords($opt) ? 0 : 1);
case '--change':
    exit(action_changePasswords($opt) ? 0 : 1);
}
error_exit("No action specified (--init or --change)\n");

function error_exit($sMsg, $errorcode = 1)
{
    fwrite(STDERR, $sMsg);
    exit($errorcode);
}

function action_initPasswords($opt)
{
    $bFirstBoot = FALSE;
    $passwords = load_keys();
    if (!isset($passwords['mysqlrootpwd'])) {
    	$bFirstBoot = TRUE;

        check_mysql_running();

        // Prompt for the MySQL password for this system
        if (!elastix_prompt_mysql_passwd()) return FALSE;
    } else {
    	print "Password configuration already present.\n";
    }
    
    // Read the MySQL root password for this system
    $passwords = load_keys();
    
    // The scripts placed in /var/spool/elastix-mysqldbscripts should be executed now.
    foreach (glob('/var/spool/elastix-mysqldbscripts/*.sql') as $dbscript) {
    	if (file_exists($dbscript)) {
            check_mysql_running();            

    		print "Applying MySQL script $dbscript ...\n";
            $output = $retval = NULL;
            exec('mysql -u root '.escapeshellarg('-p'.$passwords['mysqlrootpwd']).' < '.escapeshellarg($dbscript), $output, $retval);
            if ($retval != 0) return FALSE;
            unlink($dbscript);
    	}
    }
    
    // Init web passwords if first boot
    if ($bFirstBoot) {
        check_mysql_running();
    
        if (!elastix_prompt_web_passwd(FALSE)) return FALSE;
    }
    return TRUE;
}

function action_changePasswords($opt)
{
    if (!file_exists(PASSWD_PATH)) {
        fwrite(STDERR, 'Password configuration /etc/elastix.conf not present.');
    	return FALSE;
    }
    if (!file_exists('/etc/amportal.conf')) {
    	fwrite(STDERR, 'Configuration file /etc/amportal.conf not present');
        return FALSE;
    }
    
    check_mysql_running();
    
    // Prompt for the MySQL password for this system
    if (!elastix_prompt_mysql_passwd()) return FALSE;
    
    // Prompt for web password
    if (!elastix_prompt_web_passwd(TRUE)) return FALSE;

    return TRUE;
}

function check_mysql_running()
{
    global $g_mysql_running;

    if ($g_mysql_running) return TRUE;
	
	$output = $retval = NULL;
    exec('/sbin/service mysqld status', $output, $retval);
    if ($retval == 0) {
    	exec('/sbin/service mysqld start', $output, $retval);
        if ($retval) die("FATAL: unable to start MySQL database server!\n");
    }
    $g_mysql_running = TRUE;
}

function elastix_prompt_mysql_passwd()
{
	$sDialogPurpose =
        "The Elastix system uses the open-source database engine MySQL for " .
        "storage of important telephony information. In order to protect your " .
        "data, a master password must be set up for the database.\n\n" .
        "This screen will now ask for a password for the 'root' account of ".
        "MySQL.\n\n";

    // Read and set new MySQL root password
    $sMySQL_passwd = array('', '');
    while ($sMySQL_passwd[0] == '') {
        while ($sMySQL_passwd[0] == '') {
            $retstatus = dialog_passwordbox(
                BACKTITLE." (Screen 1 of 4)",
                "$sDialogPurpose Please enter your new MySQL root password:",
                16, 70);
            if ($retstatus['retval'] != 0) return FALSE; 
            $sMySQL_passwd[0] = $retstatus['password'];
            if ($sMySQL_passwd[0] == '') {
                dialog_msgbox(BACKTITLE,
                    'MySQL root password must be nonempty.',
                    7, 40);
            } elseif (!preg_match(REGEXP_VALID_PASSWORD, $sMySQL_passwd[0])) {
                $sMySQL_passwd[0] = '';              
                dialog_msgbox(BACKTITLE,
                    'Admin password may only contain alphanumeric characters, spaces, or the following: .@=_!-.',
                    7, 40);
            }
        }
        while ($sMySQL_passwd[1] == '') {
            $retstatus = dialog_passwordbox(
                BACKTITLE." (Screen 2 of 4)",
                "Please (re)confirm your new MySQL root password:",
                10, 70);
            if ($retstatus['retval'] != 0) return FALSE;
            $sMySQL_passwd[1] = $retstatus['password'];
        }
        
        if ($sMySQL_passwd[0] != $sMySQL_passwd[1]) {
            dialog_msgbox(BACKTITLE,
                'Password and confirmation do not match!',
                7, 40);
            $sMySQL_passwd[0] = $sMySQL_passwd[1] = '';
        }
    }
    
    if (!set_mysql_root_password($sMySQL_passwd[0])) return FALSE;
    if (!set_cyrus_password($sMySQL_passwd[0])) return FALSE;
    
    print "The password for mysql and cyrus admin were successfully changed!\n";
    sleep(3);

    return TRUE;
}

function set_mysql_root_password($sNewPassword)
{
    // Load old mysql password from file, if it exists
    $sMySQL_oldpasswd = NULL;
    $passwords = load_keys();
    if (isset($passwords['mysqlrootpwd']))
        $sMySQL_oldpasswd = $passwords['mysqlrootpwd'];
    
    // Set new MySQL root password, immediately save on success
    try {
        $db = new PDO('mysql:host=localhost', 'root', $sMySQL_oldpasswd);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        // MySQL does not support preparing a GRANT statement
        $quotedPwd = $db->quote($sNewPassword);
        if ($quotedPwd === FALSE) {
            fwrite(STDERR, 'FATAL: failed to quote new MySQL password');
        	return FALSE;
        }
        $db->exec("GRANT USAGE ON *.* TO root@localhost IDENTIFIED BY $quotedPwd");
        $db->exec("GRANT USAGE ON *.* TO root IDENTIFIED BY $quotedPwd");
        $db = NULL;

        $passwords['mysqlrootpwd'] = $sNewPassword;
        save_keys($passwords);
    } catch (PDOException $e) {
        fwrite(STDERR, 'FATAL: unable to change mysql root password: '.$e->getMessage()."\n");
        return FALSE;
    }
    
	return TRUE;
}

function set_cyrus_password($sNewPassword)
{
    // Run saslpasswd2 to set the new password
    $r = popen('/usr/sbin/saslpasswd2 -c cyrus -u example.com', 'w');
    if (!is_resource($r)) {
        fwrite(STDERR, "FATAL: failed to open pipe to saslpasswd2\n");
        return FALSE;
    }
    fwrite($r, $sNewPassword);
    $ret = pclose($r);
    if ($ret != 0) {
        fwrite(STDERR, "ERR: unable to set new cyrus password via saslpasswd2\n");
    	return FALSE;
    }
    
    // Store just-changed password
    $passwords = load_keys();
    $passwords['cyrususerpwd'] = $sNewPassword;
    save_keys($passwords);
    
    chmod('/etc/sasldb2', 0644);
    
    return TRUE;
}

function elastix_prompt_web_passwd($bRestart)
{
    $sDialogPurpose =
        "Several Elastix components have administrative interfaces that can " .
        "be used through the Web. A web login password must be set for these " .
        "components in order to prevent unauthorized access to these " .
        "administration interfaces.\n\n" .
        "This screen will now ask for a password for user 'admin' that will " .
        "be used for: Elastix Web Login, FreePBX, VTiger, A2Billing and " .
        "FOP.\n\n";

    // Read and set new FreePBX admin password. This procedure works with FreePBX 2.7.0
    $sFreePBX_passwd = array('', '');
    while ($sFreePBX_passwd[0] == '') {
        while ($sFreePBX_passwd[0] == '') {
            $retstatus = dialog_passwordbox(
                BACKTITLE." (Screen 3 of 4)",
                "$sDialogPurpose Please enter your new password for freePBX 'admin':",
                16, 70);
            if ($retstatus['retval'] != 0) return FALSE;
            $sFreePBX_passwd[0] = $retstatus['password'];
            if ($sFreePBX_passwd[0] == '') {
                dialog_msgbox(BACKTITLE,
                    'Admin password must be nonempty.',
                    7, 40);
            } elseif (!preg_match(REGEXP_VALID_PASSWORD, $sFreePBX_passwd[0])) {
                $sFreePBX_passwd[0] = '';
                dialog_msgbox(BACKTITLE,
                    'Admin password may only contain alphanumeric characters, spaces, or the following: .@=_!<>-.',
                    7, 40);
            }
        }
        while ($sFreePBX_passwd[1] == '') {
            $retstatus = dialog_passwordbox(
                BACKTITLE." (Screen 4 of 4)",
                "Please (re)confirm your new password for freePBX 'admin':",
                10, 70);
            if ($retstatus['retval'] != 0) return FALSE;
            $sFreePBX_passwd[1] = $retstatus['password'];
        }
        if ($sFreePBX_passwd[0] != $sFreePBX_passwd[1]) {
            dialog_msgbox(BACKTITLE,
                'Password and confirmation do not match!',
                7, 40);
            $sFreePBX_passwd[0] = $sFreePBX_passwd[1] = '';
        }
    }

    // Open database connection used in several updates
    $passwords = load_keys();
    if (!isset($passwords['mysqlrootpwd'])) {
        fwrite(STDERR, "FATAL: unable to extract MySQL root password\n");
    	return FALSE;
    }
    try {
        $db = new PDO('mysql:host=localhost', 'root', $passwords['mysqlrootpwd']);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        fwrite(STDERR, 'FATAL: unable to open database connection: '.$e->getMessage()."\n");
        return FALSE;
    }

    // MySQL does not support preparing a GRANT statement
    $quotedPwd = $db->quote($sFreePBX_passwd[0]);
    if ($quotedPwd === FALSE) {
        fwrite(STDERR, "FATAL: failed to quote new password\n");
        return FALSE;
    }
    
    /* The following list defines one element for each known password that needs
     * to be changed to match the password entered above. Each element defines
     * targets on sqlite, mysql, or files. For sqlite, a list of database files
     * is listed, along with the update query and the query parameters. For
     * mysql, the same is done, but the update must indicate the schema name in
     * all of the tables. For files, each file has a PCRE regexp that locates
     * the target line, optionally with a target old password, and the contents
     * of the line that includes the new password. Some cases need additional
     * evaluation and are added dynamically after this declaration. 
     * 
     * For mysql case, a third optional item contains a list of tables to check
     * for. If supplied, all tables listed must be present for the query to 
     * apply.
     */
    $updateList = array(
        'FreePBX database password' => array(
            'sqlite'    =>  NULL,
            'mysql'     =>  array(
                array(
                    "GRANT USAGE ON *.* TO asteriskuser@localhost IDENTIFIED BY $quotedPwd",
                    array()
                ),
            ),
            'file'      =>  array(
                array(
                    '/etc/amportal.conf',
                    '^AMPDBPASS=',
                    'AMPDBPASS='.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/asterisk/res_mysql.conf',
                    '^dbpass\s*=\s*',
                    'dbpass = '.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/asterisk/res_config_mysql.conf',
                    '^dbpass\s*=\s*',
                    'dbpass = '.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/asterisk/cbmysql.conf',
                    '^password=',
                    'password='.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/asterisk/cdr_mysql.conf',
                    '^password\s*=\s*',
                    'password = '.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/asterisk/extensions_additional.conf',
                    '^AMPDBPASS =',
                    'AMPDBPASS ='.$sFreePBX_passwd[0],
                ),
            ),
        ),
        'FreePBX admin password' => array(
            'sqlite'    =>  NULL,
            'mysql'     =>  array(
                array(
                    'UPDATE asterisk.ampusers SET password_sha1 = SHA1(?) WHERE username = ?',
                    array($sFreePBX_passwd[0], 'admin')
                ),
            ),
            'file'      =>  array(
                array(
                    '/etc/freepbx.conf',
                    '^\$amp_conf\[\'AMPDBPASS\'\]\s*=\s*',
                    '$amp_conf[\'AMPDBPASS\']  = \''.$sFreePBX_passwd[0].'\';',
                ),
            ),
        ),
        'FreePBX ARI password' => array(
            'sqlite'    =>  NULL,
            'mysql'     =>  array(
                array(
                    'UPDATE asterisk.freepbx_settings SET value = ? WHERE keyword = ?',
                    array($sFreePBX_passwd[0],'ARI_ADMIN_PASSWORD'),
                    array(array('asterisk', 'freepbx_settings'))
                ),
            ),
            'file'      =>  array(
                array(
                    '/etc/amportal.conf',
                    '^ARI_ADMIN_PASSWORD=',
                    'ARI_ADMIN_PASSWORD='.$sFreePBX_passwd[0],
                ),
            ),
        ),
        'Flash Operator Panel password' => array(
            'sqlite'    =>  NULL,
            'mysql'     =>  array(
                array(
                    'UPDATE asterisk.freepbx_settings SET value = ? WHERE keyword = ?',
                    array($sFreePBX_passwd[0],'FOPPASSWORD'),
                    array(array('asterisk', 'freepbx_settings'))
                ),
                array(
                    'UPDATE asterisk.freepbx_settings SET value = ? WHERE keyword = ?',
                    array('/var/www/html/admin/modules/fw_fop/','FOPWEBROOT'),
                    array(array('asterisk', 'freepbx_settings'))
                ),
            ),
            'file'      =>  array(
                array(
                    '/etc/amportal.conf',
                    '^FOPPASSWORD=',
                    'FOPPASSWORD='.$sFreePBX_passwd[0],
                ),
            ),
        ),
        'Asterisk Manager Interface password' => array(
            'sqlite'    =>  NULL,
            'mysql'     =>   array(
                array(
                    'UPDATE asterisk.freepbx_settings SET value = ? WHERE keyword = ?',
                    array($sFreePBX_passwd[0],'AMPMGRPASS'),
                    array(array('asterisk', 'freepbx_settings'))
                ),
            ),
            'file'      =>  array(
                array(
                    '/etc/asterisk/manager.conf',
                    array(
                        'custom', 'change_ami_password'
                    ),
                    'secret = '.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/amportal.conf',
                    '^AMPMGRPASS=',
                    'AMPMGRPASS='.$sFreePBX_passwd[0],
                ),
                array(
                    '/etc/asterisk/extensions_additional.conf',
                    '^AMPMGRPASS =',
                    'AMPMGRPASS ='.$sFreePBX_passwd[0],
                ),
            ),
        ),
        'Elastix admin password' => array(
            'sqlite'    =>  array(
                array(
                    '/var/www/db/acl.db',
                    'UPDATE acl_user SET md5_password = ? WHERE name = ?',
                    array(md5($sFreePBX_passwd[0]), 'admin'),
                ),
            ),
            'mysql'     =>  NULL,
            'file'      =>  NULL,
        ),
    );

    // List all databases (cannot list specific databases with LIKE)
    $databases = NULL;
    try {
    	$sth = $db->prepare('SHOW DATABASES');
        $sth->execute();
        $databases = $sth->fetchAll(PDO::FETCH_COLUMN, 0);
    } catch (PDOException $e) {
        fwrite(STDERR, "FATAL: unable to list databases: ".$e->getMessage()."\n");
        return FALSE;
    }

    // Conditionally add CallCenter update for AMI password
    try {
        if (!in_array('call_center', $databases)) {
            print "No Elastix CallCenter database found.\n";
        } else {
            print "Found Elastix CallCenter database.\n";
            $sth = $db->prepare('SELECT config_key, config_value FROM call_center.valor_config WHERE config_key LIKE ?');
            $sth->execute(array('asterisk.%'));
            $values = $sth->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE);
            if (isset($values['asterisk.asthost']) && 
                in_array($values['asterisk.asthost'], array('127.0.0.1', 'localhost')) &&
                isset($values['asterisk.astuser']) &&
                $values['asterisk.astuser'] == 'admin') {
                    if (!is_array($updateList['Asterisk Manager Interface password']['mysql']))
                        $updateList['Asterisk Manager Interface password']['mysql'] = array();
                	$updateList['Asterisk Manager Interface password']['mysql'][] = array(
                        'UPDATE valor_config SET config_value = ? WHERE config_key = ?',
                        array($sFreePBX_passwd[0], 'asterisk.astpass'),
                    );
            }
        }
    } catch (PDOException $e) {
        fwrite(STDERR, "FATAL: unable to check whether CallCenter references AMI: ".$e->getMessage()."\n");
        return FALSE;
    }	

    // Conditionally add updates for A2Billing
    try {
        if (!in_array('mya2billing', $databases)) {
        	print "No A2Billing database found.\n";
        } else {
        	print "Found A2Billing database.\n";
            $updateList['A2Billing password'] = array(
                'sqlite'    =>  NULL,
                'mysql'     =>  array(
                    array(
                        'UPDATE mya2billing.cc_ui_authen SET pwd_encoded = ? WHERE login = ? OR login = ?',
                        array(hash('whirlpool', $sFreePBX_passwd[0]), 'admin', 'root'),
                    ),
                    array(
                        'UPDATE mya2billing.cc_config SET config_value = ? WHERE config_group_title = ? AND config_key = ?',
                        array('admin', 'global', 'manager_username')
                    ),
                    array(
                        'UPDATE mya2billing.cc_config SET config_value = ? WHERE config_group_title = ? AND config_key = ?',
                        array($sFreePBX_passwd[0], 'global', 'manager_secret'),
                    ),
                    array(
                        'UPDATE mya2billing.cc_server_manager SET manager_username = ?, manager_secret = ? WHERE id = ? AND id_group = ?',
                        array('admin', $sFreePBX_passwd[0], 1, 1),
                    ),
                ),
                'file'      =>  NULL,
            );
            
            // Conditionally update or remove redundant 'root' user as required
            $sth = $db->prepare('SELECT count(*) FROM mya2billing.cc_ui_authen WHERE login = ?');
            $sth->execute(array('admin'));
            $iNumTotal = $sth->fetch(PDO::FETCH_COLUMN, 0);
            $sth->closeCursor();
            if (!is_null($iNumTotal) && $iNumTotal > 0) {
                // Remove redundant user root
                $updateList['A2Billing password']['mysql'][] = array(
                    'DELETE FROM mya2billing.cc_ui_authen WHERE login = ?',
                    array('root'),
                );
            } else {
                // Shift root user to admin
                $updateList['A2Billing password']['mysql'][] = array(
                    'UPDATE mya2billing.cc_ui_authen SET login = ? WHERE login = ?',
                    array('admin', 'root'),
                );
            }
        }
    } catch (PDOException $e) {
        fwrite(STDERR, "FATAL: unable to check whether A2Billing database has 'root': ".$e->getMessage()."\n");
        return FALSE;
    }

    // Conditionally add updates for VTigerCRM password
    $sVTigerDB = NULL;
    if (in_array('vtigercrm510', $databases))
        $sVTigerDB = 'vtigercrm510';
    if (in_array('vtigercrm521', $databases))
        $sVTigerDB = 'vtigercrm521';
    if (is_null($sVTigerDB)) {
    	print "No VTigerCRM database found.\n";
    } else {
    	print "Found VTigerCRM database $sVTigerDB\n";
        $updateList['VTigerCRM password'] = array(
            'sqlite'    =>  NULL,
            'mysql'     =>  array(
                array(
                    "UPDATE $sVTigerDB.vtiger_users SET user_password = ENCRYPT(?, CONCAT(?, SUBSTRING(? FROM 1 FOR 2), ?)), user_hash = md5(?) WHERE user_name = ?",
                    array($sFreePBX_passwd[0], '$1$', 'admin', '$', $sFreePBX_passwd[0], 'admin'),
                ),
            ),
            'file'      =>  NULL,
        );
    }

    // Prepare query to check if MySQL table exists
    try {
        $sth_tableExists = $db->prepare(
            'SELECT COUNT(*) AS N FROM information_schema.TABLES '.
            'WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?');
    } catch (PDOException $e) {
        fwrite(STDERR, "FATAL: unable to prepare table check query: ".$e->getMessage()."\n");
        return FALSE;
    }

    foreach ($updateList as $k => $updateItem) {
    	print "Updating $k: ";

        // Update all instances of the password in sqlite databases
        if (!is_null($updateItem['sqlite'])) {
            print "sqlite... ";
        	foreach ($updateItem['sqlite'] as $updateSqliteItem) {
        		try {
        			$dbsqlite = new PDO('sqlite:'.$updateSqliteItem[0]);
                    $dbsqlite->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                    $sth = $dbsqlite->prepare($updateSqliteItem[1]);
                    $sth->execute($updateSqliteItem[2]);
                    $sth = NULL;
                    $dbsqlite = NULL;
        		} catch (PDOException $e) {
                    fwrite(STDERR, "FATAL: unable to update $k: ".$e->getMessage()."\n");
        			return FALSE;
        		}
        	}
        }
        
        // Update all instances of the password in MySQL
        if (!is_null($updateItem['mysql'])) {
            print "mysql... ";
        	foreach ($updateItem['mysql'] as $updateMysqlItem) {
        		try {
        			// Check whether this is an optional update
        			$bAllTablesExist = TRUE;
        			if (count($updateMysqlItem) > 2) {
        			    foreach ($updateMysqlItem[2] as $t) {
        			        $sth_tableExists->execute($t);
        			        $tuple = $sth_tableExists->fetch(PDO::FETCH_ASSOC);
        			        $sth_tableExists->closeCursor();
        			        if ($tuple['N'] <= 0) {
        			            $bAllTablesExist = FALSE;
        			            break;
        			        }
        			    }
        			}
        			if (!$bAllTablesExist) continue;
        			
        			if (strpos($updateMysqlItem[0], 'GRANT') === 0) {
        				// MySQL does not support preparing a GRANT statement
                        $db->exec($updateMysqlItem[0]);
        			} else {
        				$sth = $db->prepare($updateMysqlItem[0]);
                        $sth->execute($updateMysqlItem[1]);
                        $sth = NULL;
        			}
        		} catch (PDOException $e) {
                    fwrite(STDERR, "FATAL: unable to update $k: ".$e->getMessage()."\n");
        			return FALSE;
        		}
        	}
        }
        
        // Update all instances of the password in system files
        if (!is_null($updateItem['file'])) {
            print "files... ";
            foreach ($updateItem['file'] as $fileinfo) {
                if (file_exists($fileinfo[0])) {
                    $content = file($fileinfo[0]);
                    if (is_array($fileinfo[1])) {
                        switch ($fileinfo[1][0]) {
                        case 'custom':
                            if (function_exists($fileinfo[1][1]))
                                $fileinfo[1][1]($content, $sFreePBX_passwd[0]);
                            break;
                        }
                    } else {
                        for ($i = 0; $i < count($content); $i++) {
                            if (preg_match("/".$fileinfo[1]."/", rtrim($content[$i], "\r\n"))) {
                                $content[$i] = $fileinfo[2]."\n";
                                break;
                            }
                        }
                    }
                    file_put_contents($fileinfo[0], $content);
                }
            }
        }
        
        print " updated\n";
    }

    // Save newly-updated password
    $passwords['amiadminpwd'] = $sFreePBX_passwd[0];
    save_keys($passwords);

    if ($bRestart) {    
        print "Restarting amportal...";
        system('/usr/sbin/amportal restart > /dev/null 2>&1');
        print " restarted\n";
    }

    return TRUE;
}

function change_ami_password(&$content, $sNewPassword)
{
    $bAdmin = FALSE;
    for ($i = 0; $i < count($content); $i++) {
        $regs = NULL;
        if (preg_match('/^\[(\w+)\]/', $content[$i], $regs)) {
            $bAdmin = ($regs[1] == 'admin');
        } elseif ($bAdmin && preg_match('/^secret\s*=\s*/', $content[$i])) {
            $content[$i] = "secret = $sNewPassword\n";
        }
    }
}

function dialog_msgbox($backtitle, $msgbox, $height, $width)
{
    $height = (int)$height;
    $width = (int)$width;
    passthru('/usr/bin/dialog'.
        ' --backtitle '.escapeshellarg($backtitle).
        ' --msgbox '.escapeshellarg($msgbox).
        " $height $width");
}

function dialog_passwordbox($backtitle, $msgbox, $height, $width)
{
	global $option;
    $height = (int)$height;
    $width = (int)$width;

    $pipes = NULL;
    $pipespec = array(
        0 => STDIN,
        1 => STDOUT,
        2 => STDERR,
        3 => array('pipe', 'w'));
        
	if ($option[0] == "--init"){
	   $cncl=' --no-cancel';
    }
     
    $r = @proc_open('/usr/bin/dialog'.
		$cncl.
        ' --output-fd 3'.
        ' --backtitle '.escapeshellarg($backtitle).
        ' --insecure --passwordbox '.escapeshellarg($msgbox).
        " $height $width",
        $pipespec,
        $pipes);
    if (is_resource($r)) {
        $password = stream_get_contents($pipes[3]);
        fclose($pipes[3]);
        return array('retval' => proc_close($r), 'password' => $password);
    } else {
        return NULL;
    }
}

// Need custom function to load conf file, odd characters choke parse_ini_file()
function load_keys()
{
	$keys = array();
    if (file_exists(PASSWD_PATH)) foreach (file(PASSWD_PATH) as $s) {
    	$s = rtrim($s, "\r\n");
        $regs = NULL;
        if (preg_match('/^(\w+)=(.*)$/', $s, $regs))
            $keys[$regs[1]] = $regs[2];
    }
    return $keys;
}

function save_keys($keys)
{
	$s = '';
    foreach ($keys as $k => $v) $s.= "$k=$v\n";
    file_put_contents(PASSWD_PATH, $s);
    chmod(PASSWD_PATH, 0600);
    chown(PASSWD_PATH, 'asterisk');
    chgrp(PASSWD_PATH, 'asterisk');
}
?>
