Location: PHPKode > projects > web-cp - Web Hosting Control Panel > webcp/server/webcp.php
#!/usr/bin/php
<?	/*
	// File:	webcp.php
	// Purpose:	web://cp CGI Daemon
	// Creation:	2002-02-28
	// Author:	Felix <hide@address.com>
	*/

//explicitly set error level for people who have changed their php.ini defaults
error_reporting(E_ALL & ~E_NOTICE);

// Change working directory
chdir(dirname(__FILE__));

// Include configuration, system and interface functions
include("../web/config.inc.php");
include("../web/functions.inc.phps");
// server functions
include("functions.inc.phps");

// Make sure the php CGI has the needed modules
$i = 0;
unset($error);
if (!extension_loaded('mysql'))
	$error[++$i] = "PHP Error: The MySQL module is required (configure PHP '--with-mysql=/usr')\n";
if (!extension_loaded('ftp'))
	$error[++$i] = "PHP Error: The FTP module is required (configure PHP '--enable-ftp')\n";
if (!extension_loaded('zlib'))
	$error[++$i] = "PHP Error: The Zlib module is required (configure PHP '--with-zlib-dir=/usr')\n";
if (!extension_loaded('posix'))
	$error[++$i] = "PHP Error: The POSIX module is required (configure PHP '--enable-posix')\n";
if (!extension_loaded('pcntl'))
	$error[++$i] = "PHP Error: The Process Control module is required (configure PHP '--enable-pcntl')\n";
if (!ini_get("register_argc_argv"))
       $error[++$i] = "Variable register_argc_argv must be set to On inside php.ini\n";

// Connect to the database
@mysql_connect($cfg['dbhost'], $cfg['dbuser'], $cfg['dbpass']);
@mysql_select_db($cfg['dbname']);

if (isset($error)) {
	webcp_log(0,0,'webcp.php',implode("\n",$error),0,1);
	exit;
}
// Run from root only
if (posix_getuid() != 0) {
	webcp_log(0,0,'webcp.php',"This program must be run as root.",0,1);
	exit;
}

// Check if we are run interactively or with the -d switch; keep on going or become a daemon
$args = trim(next($HTTP_SERVER_VARS["argv"]));
if ($args == '-d' OR $args == '--daemon') {
	// Fork webcp.php
	$pid = pcntl_fork();
	$echo = 0;
	if ($pid == -1) {
		webcp_log(0,0,'webcp.php',"Error: could not fork.",0,1);
		exit;
	} else if ($pid) {
		return 0;	// we are the parent, return '0' on success
	}
	
	// detach from the controlling terminal
	if (!posix_setsid()) {
		webcp_log(0,0,'webcp.php',"Could not detach from terminal",0,1);
		exit;
	} else
		webcp_log(2,0,'webcp.php',"The web://cp daemon has been started.",0,1);
}

else {
	$echo = 1;
	webcp_log(3,0,'webcp.php',"web://cp ".$cfg['webcp']." daemon usage:
	webcp.php		(run interactively)
	webcp.php -i		(run interactively)
	webcp.php -d, --daemon	(run as daemon)
	webcp.php -h, --help	(display this help notice)
	
",0,1);
	if ($args == '-h' OR $args == '--help')
		exit;
	else {
		webcp_log(3,0,'webcp.php',"\n\n Running web://cp ".$cfg['webcp']." interactively\n use ./webcp.php -h for help, CTRL-C to exit\n==================================================\n\n",0,1);
	}
}
unset($args);

// Log Process ID
$fp = fopen($cfg['pid'],"w+");
fwrite($fp,getmypid());
fflush($fp);
fclose($fp);

// Indicate the backend is up
touch($cfg['basedir'].$cfg['statustag']);

// Initialize vars
$remapmail = FALSE;
$restarthttp = FALSE;
$restartmail = FALSE;
$restartdns = FALSE;
$domainchange = FALSE;
$userchange = FALSE;
$endlessloop = 1;

// Set no timeout (unlimited)
set_time_limit(0);

// Start endless loop
while ($endlessloop++) {
	
	// check cron.php zombies child process
	if (file_exists($cfg['pid'].'-cron')) {
		$tmp = (int)trim(implode("",file($cfg['pid'].'-cron')));
		$f_pid = pcntl_waitpid ($tmp, $f_stat, WNOHANG);
		$f_pid = pcntl_waitpid (0, $f_stat, WNOHANG);
	}
	
	// every 60 seconds, fork cron.php (webcp's scheduler)
	if (!($endlessloop % 60)) {
		webcp_log(3,0,'webcp.php',"Note: Forking cron.php",0,$echo);
    		
		$pid = pcntl_fork();
		if ($pid == -1) {
			webcp_log(0,0,"webcp.php","Fork Error: could not fork webcp.php for cron.php",0,$echo);
		} elseif (!$pid) {
			
			// Log Process ID
			$fp = fopen($cfg['pid'].'-cron',"w+");
			$mypid = getmypid();
			fwrite($fp,$mypid);
			fflush($fp);
			fclose($fp);
			
			// Set no timeout (unlimited)
			set_time_limit(0);
		
			// include cron script and stay there
			include("cron.php");
			exit;
		}
	}
	
	// Check if there is a server tag set
	$tag = commit('read');

	// Remove flag right away to make room.
	commit('remove');
	
	if ($tag) {
		
		// Scan database if flag is stop,start,restart,scan
		switch($tag['action'][0]) {
			// change configuration settings
			case 'config':
				parse_str(trim($tag['action'][1]), $config);
				foreach($config AS $key => $val) {
					// check and see if config is allowed to be changed
					if (preg_match('/^('.$cfg['allowed_cfg'].')$/', $key)) {
						// it is not already set to the same value.
						if (!isset($cfg[$key]) || (isset($cfg[$key]) && $val != $cfg[$key])) {
							// and don't quote number or boolian values
							if (is_numeric($val) || $val == 'true' || $val == 'false') {
								if (!file_edit('/\$cfg\[[\'"]'.$key.'["\']\].*?;/', '$cfg[\''.$key.'\'] = '.$val.';', $cfg['basedir'].'/config.php')) {
									file_edit("/\n\?>/", '', $cfg['basedir'].'/config.php');
									file_append("\$cfg['".$key."'] = ".$val.";\n?>", $cfg['basedir'].'/config.php');
								}
							} else {
								if (!file_edit('/\$cfg\[[\'"]'.$key.'["\']\].*?;/', '$cfg[\''.$key.'\'] = \''.$val.'\';', $cfg['basedir'].'/config.php')) {
									file_edit("/\n\?>/", '', $cfg['basedir'].'/config.php');
									file_append("\$cfg['".$key."'] = '".$val."';\n?>", $cfg['basedir'].'/config.php');
								}
							}
						}
					}
				}
				// reload webcp http server
				if ($cfg['httpd_mode'] = 'webcp') {
					if (file_exists($cfg['httpd_pid']))
						posix_kill(trim(implode('', file($cfg['httpd_pid']))), 1);
				}
				break;
			// create initial config.php
			case 'setup':
				// don't overwrite someone's custom settings
				if (!file_exists($cfg['basedir'].'/config.php')) {
					
					// write small header
					$fp = fopen($cfg['basedir'].'/config.php',"w");
					fwrite($fp, '<'.'?'."\n");
					fwrite($fp, "/**********************************************\n");
					fwrite($fp, " * Check web/config.inc.php for all settings. *\n");
					fwrite($fp, " **********************************************/\n\n");
					
					// split up single config line and enter each setting into the config.php file
					parse_str(trim($tag['action'][1]), $config);
					foreach($config AS $key => $val) {
						if (preg_match('/^('.$cfg['allowed_cfg'].')$/', $key)) {
							if (is_numeric($val) || $val == 'true' || $val == 'false') {
								// don't quote number or boolian values
								fwrite($fp, "\$cfg['".$key."'] = ".$val.";\n");
							} else {
								fwrite($fp, "\$cfg['".$key."'] = '".$val."';\n");
							}
						}
					}
					fwrite($fp, '?'.'>');
					fclose($fp);

					// change config.php to be group readable by webcp-httpd	
					if ($user = posix_getpwnam($cfg['httpd_user'])) {
						chgrp($cfg['basedir'].'/config.php', $user['gid']);
						chmod($cfg['basedir'].'/config.php', 0640);
					}
				}
				// load the newly created settings
				include($cfg['basedir'].'/config.php');

				// try to create and propagate the database
				if (@mysql_connect($cfg['dbhost'], $cfg['dbuser'], $cfg['dbpass'])) {

					if (!@mysql_select_db($cfg['dbname'])) {
						// database is missing create it
						mysql_query("CREATE DATABASE $cfg[dbname]");
					}
					$dbp = mysql_query("SHOW TABLES FROM $cfg[dbname]");
					if (@mysql_num_rows($dbp) === 0) {
						// database is empty, fill it. TODO: maybe we shouldn't rely on mysql 
						empty($cfg['dbpass']) ? $tmp = '' : $tmp = "-p$cfg[dbpass]";
						exec($cfg['prog']['mysql']." -s -u $cfg[dbuser] $tmp $cfg[dbname] < $cfg[basedir]/webcp.sql");
						exec($cfg['prog']['mysql']." -s -u $cfg[dbuser] $tmp $cfg[dbname] < $cfg[basedir]/help-$cfg[defaultlang].sql");
					}
				} else {
					webcp_log(0,0,'webcp.php',"Error:  Could not connect to database server",0,$echo);
				}

				// reload webcp http server
				if ($cfg['httpd_mode'] = 'webcp') {
					if (file_exists($cfg['httpd_pid']))
						posix_kill(trim(implode('', file($cfg['httpd_pid']))), 1);
				}
				break;

			// System Reboot
			case  'reboot':
				exec($cfg['prog']['shut']." -r now");
				
				// Shut webcp.php gracefully: remove pid file and die
				unlink($cfg['pid']);
				exit;

			// stop/start/restart program or network
			case 'start':
			case 'stop':
			case 'restart':
				// more sysv init stuff here.
				webcp_log(3,0,'webcp.php',$tag['action'][0]." ".$tag['action'][1],0,$echo);
				exec($cfg['init'][$tag['action'][1]]." ".$tag['action'][0]);
				
			// Scan databases users and domains for changes to apply
			case 'scan':
				// Connect to database
				if (!@mysql_connect($cfg['dbhost'], $cfg['dbuser'], $cfg['dbpass'])) {
					webcp_log(0,0,'webcp.php',"Error:  Could not connect to database server",0,$echo);
					break;
				}
				else {
					// Select correct database and go on.
					if (!@mysql_select_db($cfg['dbname'])) {
						webcp_log(0,0,'webcp.php',"Error:  Could not select database",0,$echo);
						exit;
					}
					
					// Begin loop on the db check to insure we don't get into a race situation
					do {
						// Check Domains Table
						$dbp = mysql_query("SELECT id FROM domains WHERE action != ''");
	   					while ($data = mysql_fetch_array($dbp)) {
	   						$tmp = fetchdata("*","domain",$data['id']);
	   						// seal check (data integrity)
	   						$hash = $tmp;
	   						$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
							$hash = crypt(md5(serialize($hash)), $cfg['key']);
							if ($hash == $tmp['hash']) {
								webcp("domain",$tmp);
		    		   				
		    		   				// interactive dump
		    		   				webcp_log(3,0,'webcp.php',"Domain ".$tmp['id']." ".$tmp['action'],0,$echo);
		    		   				
					   			// Signal a domain change
					   			$domainchange = TRUE;
					   		}
							else {
								// suspend domain
							//	$tmp['action'] = 'suspend';
								
								webcp("domain",$tmp);
								webcp_log(1,$tmp['id'],"system","Invalid Domain Seal -- Domain $tmp[id] $tmp[action]",0, $echo);
								    		   						
    		   						// Signal a domain change
					   			$domainchange = TRUE;
    		   					}
						}
						
						// Check Users Table
						$dbp = mysql_query("SELECT username FROM users WHERE action != ''");
						while ($data = mysql_fetch_array($dbp)) {
							$tmp = fetchdata("*","user",$data['username']);
							// seal check (data integrity)
	   						$hash = $tmp;
	   						$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
							$hash = crypt(md5(serialize($hash)), $cfg['key']);

							if ($hash == $tmp['hash']) {
								webcp("user",$tmp);
		   					
			   					// interactive dump
		    		   				webcp_log(3,0,'webcp.php',"User ".$tmp['username']." ".$tmp['action'],0,$echo);
					   			
								// Signal a user change
								$userchange = TRUE;
							

					   		}
							else {
								// suspend user
							//	$tmp['action'] = 'suspend';
								
								webcp("user",$tmp);
								webcp_log(0,$tmp['id'],"system","Invalid User Seal -- User $tmp[username] $tmp[action]",0,$echo);
								    		   							
    		   						// Signal a user change
								$userchange = TRUE;
    		   					}
	    		 			}
	    		 			
	    		 			// Check Mailman Table
	    		 			if ($cfg['maillist'] == 'mailman') {
							$dbp = mysql_query('SELECT id, domain, listname, admin, DECODE(password, "'.$cfg['key'].'") AS password, action FROM mailman WHERE action != ""');
							while ($data = mysql_fetch_assoc($dbp)) {
								if($data['action'] == 'c') {
									if(strlen($data['password'])<3) {
										mt_srand(time());
										$data['password'] = mt_rand(111111, 999999999);
									}
									exec($cfg['prog']['mm_new'].' "'.$data['listname'].'" "'.$data['admin'].'" "'.$data['password'].'"');
									mysql_query('UPDATE mailman SET action = "" WHERE id = "'.$data['id'].'"');
									
									// interactive dump
			    		   				webcp_log(3,0,'webcp.php',"Mailman list ".$data['listname']." created",0,$echo);
									
									$userchange = TRUE;
								}
								elseif($data['action'] == 'r') {
									exec($cfg['prog']['mm_rm'].' '.$data['listname']);
									mysql_query('DELETE FROM mailman WHERE id = '.$data['id']);
									
									// interactive dump
			    		   				webcp_log(3,0,'webcp.php',"Mailman list ".$data['listname']." removed",0,$echo);
			    		   				
									$userchange = TRUE;
								}
							}
						}
                                                
	    		 			// Fetch new db info and see if we're still looping
						$dbp = mysql_query("SELECT id FROM domains WHERE action != ''");
						$dbp1 = mysql_query("SELECT username FROM users WHERE action != ''");
						
						if (mysql_num_rows($dbp) OR mysql_num_rows($dbp1)) $continueloop = true;
						else $continueloop = false;
						
	         			} while ($continueloop);
	         		}
				break;
			case "backup":
				$backupParms = explode("|", $tag['action'][1]);
				$domains = explode("_", $backupParms[5]);
				$pid = pcntl_fork();
				webcp_log(3,0,'webcp.php',"Note: Forking backup.php",0,$echo);
				if ($pid == -1) {
					webcp_log(0,0,"webcp.php","Fork Error: could not fork webcp.php for backup.php",0,$echo);
				} elseif (!$pid) {
			
					// Log Process ID
					$fp = fopen($cfg['pid'].'-backup',"w+");
					$mypid = getmypid();
					fwrite($fp,$mypid);
					fflush($fp);
					fclose($fp);
			
					// Set no timeout (unlimited)
					set_time_limit(0);
		
					// include cron script and stay there
					include("backup.php");
					exit;
				}
				break;
			case "restore":
				$restoreFiles = explode("|", $tag['action'][1]);
				$pid = pcntl_fork();
				webcp_log(3,0,'webcp.php',"Note: Forking restore.php",0,$echo);
				if ($pid == -1) {
					webcp_log(0,0,"webcp.php","Fork Error: could not fork webcp.php for restore.php",0,$echo);
				} elseif (!$pid) {
			
					// Log Process ID
					$fp = fopen($cfg['pid'].'-restore',"w+");
					$mypid = getmypid();
					fwrite($fp,$mypid);
					fflush($fp);
					fclose($fp);
			
					// Set no timeout (unlimited)
					set_time_limit(0);
		
					// include cron script and stay there
					include("restore.php");
					exit;
				}
				break;

         	}
	 
	 	// See if we trapped any signal and update system configuration files
		if ($domainchange) {
			$domainchange = FALSE;
			updatesys("domain");
		}
		if ($userchange) {
			$userchange = FALSE;
			updatesys("user");
		}
		
		// reload / restart services as appropriate
		reload_services();
	}

	// Sleep for 1 second and loop!
	sleep(1);
}

?>
Return current item: web-cp - Web Hosting Control Panel