2.0) define('POSTFIX_LOCALBASE', '/usr/pbi/postfix-' . php_uname("m")); else define('POSTFIX_LOCALBASE','/usr/local'); $uname=posix_uname(); if ($uname['machine']=='amd64') ini_set('memory_limit', '250M'); function px_text_area_decode($text){ return preg_replace('/\r\n/', "\n",base64_decode($text)); } function px_get_real_interface_address($iface) { global $config; $iface = convert_friendly_interface_to_real_interface_name($iface); $line = trim(shell_exec("ifconfig $iface | grep inet | grep -v inet6")); $postfix_enabled=$config['installedpackages']['postfix']['config'][0]['enable_postfix']; list($dummy, $ip, $dummy2, $netmask) = explode(" ", $line); return array($ip, long2ip(hexdec($netmask))); } function sync_relay_recipients($via_cron="cron"){ global $config,$g; #relay recipients if ($config['installedpackages']['postfixrecipients']['config']) { $relay_recipients=""; $relay_ldap_recipients=""; $ad_export= "/usr/local/bin/adexport.pl"; $postfix_enabled=$config['installedpackages']['postfix']['config'][0]['enable_postfix']; if (is_array($config['installedpackages']['postfixrecipients']['config'])) { $relay_ldap_recipients=""; $postfix_recipients_config=$config['installedpackages']['postfixrecipients']['config'][0]; if($postfix_recipients_config['enable_url'] && is_URL($postfix_recipients_config['custom_url'])){ print "extracting from ".$postfix_recipients_config['custom_url']."..."; $relay_recipients .= file_get_contents($postfix_recipients_config['custom_url']); print "(". count(file($postfix_recipients_config['custom_url'])).")\n"; } if($postfix_recipients_config['custom_recipients']) $relay_recipients .= px_text_area_decode($postfix_recipients_config['custom_recipients']); if($postfix_recipients_config['enable_ldap']){ #validate cront job if ($via_cron == "gui"){ #running via pfsense gui, not time for ldap fetch. $ldap_recipients= POSTFIX_LOCALBASE. '/etc/postfix/relay_ldap_recipients.txt'; if (!file_exists($ldap_recipients)) system('/usr/bin/touch '. $ldap_recipients); $relay_ldap_recipients=file_get_contents($ldap_recipients); } else{ #running via crontab, time to get ldap content. $ldap_temp=array(); foreach ($postfix_recipients_config['row'] as $postfix_ldap) { print "extracting from ".$postfix_ldap['dc']."..."; $filename=POSTFIX_LOCALBASE."/etc/postfix/relay_ldap_recipients.".$postfix_ldap['dc'].".txt"; exec($ad_export." ".$postfix_ldap['dc']." ".$postfix_ldap['cn']." ".$postfix_ldap['username']." ".$postfix_ldap['password'],$ldap_fetch,$status); if ($status == 0){ #write backup conf for ldap server $fp=fopen($filename,"w+"); foreach($ldap_fetch as $key => $value) fwrite($fp,$value."\n"); fclose($fp); } else{ if (file_exists($filename)) { #LDAP fetch failed...read backup file. print "Restoring backup file for ".$postfix_ldap['dc']."..."; $ldap_fetch=file($filename); } else{ #we never got any info from this server. print "There is no backup file for ".$postfix_ldap['dc']."..."; $ldap_fetch=array(); } } $ldap_all = array_merge($ldap_temp,$ldap_fetch); $ldap_temp=$ldap_all; print "(".count($ldap_fetch).")\n"; $ldap_fetch=array(); } $ldap_unique=array_unique($ldap_all); print "Total ldap recipients:".count($ldap_all)."\tunique:".count($ldap_unique)."\n"; foreach($ldap_unique as $recipient) $relay_ldap_recipients.=($recipient != ""?preg_replace("/\s+/","",$recipient)." OK\n":""); #save ldap relay recipients file_put_contents(POSTFIX_LOCALBASE."/etc/postfix/relay_ldap_recipients.txt",$relay_ldap_recipients, LOCK_EX); } } } #save all relay recipients, remove duplicates and reload postfix $recipients_file=POSTFIX_LOCALBASE."/etc/postfix/relay_recipients"; file_put_contents($recipients_file.".unsort",$relay_ldap_recipients."\n".$relay_recipients, LOCK_EX); exec('/usr/bin/sort -u '.$recipients_file.'.unsort > '.$recipients_file); unlink_if_exists($recipients_file.'.unsort'); exec(POSTFIX_LOCALBASE."/sbin/postmap ".POSTFIX_LOCALBASE."/etc/postfix/relay_recipients"); mwexec("/usr/local/sbin/postfix reload"); } if($relay_recipients !="" || $relay_ldap_recipients!="") return("relay_recipient_maps = hash:".POSTFIX_LOCALBASE."/etc/postfix/relay_recipients\n"); } function check_cron(){ global $config, $g; #check crontab $new_cron=array(); $cron_cmd_sqlite = ""; $cron_postfix_sqlite=""; $cron_cmd= "/usr/local/bin/php -q /usr/local/www/postfix_recipients.php"; $postfix_enabled=$config['installedpackages']['postfix']['config'][0]['enable_postfix']; #check ldap update if (is_array($config['installedpackages']['postfixrecipients']['config'])) $postfix_recipients_config=$config['installedpackages']['postfixrecipients']['config'][0]; if(preg_match("/(\d+)(\w)/",$postfix_recipients_config['freq'],$matches)){ $cron_postfix=array("minute" => "*", "hour" => "*", "mday" => "*", "month" => "*", "wday" => "*", "who" => "root", "command"=> $cron_cmd); switch ($matches[2]){ case m: $cron_postfix["minute"]="*/".$matches[1]; break; case h: $cron_postfix["minute"]="0"; $cron_postfix["hour"]="*/".$matches[1]; break; case d: $cron_postfix["minute"]="0"; $cron_postfix["hour"]="0"; $cron_postfix["mday"]="*/".$matches[1]; break; default: $input_errors[] = "A valid number with a time reference is required for the field 'Frequency'"; } } #check crontab Sqlite databases if (is_array($config['installedpackages']['postfix']['config']) && $postfix_enabled=="on"){ $cron_sqlite_queue=$config['installedpackages']['postfix']['config'][0]['update_sqlite']; $cron_cmd_sqlite="/usr/local/bin/php -q /usr/local/www/postfix.php"; if ($cron_sqlite_queue != "" && $cron_sqlite_queue != "never"){ $cron_postfix_sqlite=array("minute" => "*", "hour" => "*", "mday" => "*", "month" => "*", "wday" => "*", "who" => "root", "command"=> ""); switch ($cron_sqlite_queue){ case '01min': $cron_postfix_sqlite["command"] = $cron_cmd_sqlite ." 01min"; break; case '10min': $cron_postfix_sqlite["minute"]="*/10"; $cron_postfix_sqlite["command"] = $cron_cmd_sqlite ." 10min"; break; case '01hour': $cron_postfix_sqlite["minute"]="0"; $cron_postfix_sqlite["command"] = $cron_cmd_sqlite ." 01hour"; break; case '24hours': $cron_postfix_sqlite["minute"]="0"; $cron_postfix_sqlite["hour"]="0"; $cron_postfix_sqlite["command"] = $cron_cmd_sqlite ." 24hours"; break; } } } #check crontab relay recipients $cron_found=""; if (is_array($config['cron']['item'])){ #print "
";
				foreach($config['cron']['item'] as $cron){
					#check valid_recipients cron
					if ($cron["command"] == $cron_cmd){
						#postfix cron cmd found
						if($postfix_enabled=="on"){
							$cron_found=$cron;
							if($postfix_recipients_config['enable_ldap'] || $postfix_recipients_config['enable_url']){
								#update cron schedule
								$new_cron['item'][]=$cron_postfix;
								}
							}
						}
					#check sqlite update queue	
					else if(!preg_match("/.usr.local.www.postfix.php/",$cron["command"])){
						#keep all non postfix cron cmds if not empty
						if ($cron["command"] != "")
							$new_cron['item'][]=$cron;
						}
					}
			$write_cron=1;
			# Check if crontab must be changed to valid recipients cmd
			if ($postfix_recipients_config['enable_ldap'] || $postfix_recipients_config['enable_url']){
				if ($cron_found!=$cron_postfix){
					#update postfix cron schedule	
					if (! is_array($cron_found) && $postfix_enabled=="on")
						$new_cron['item'][]=$cron_postfix;
					$write_cron=1;
					}
				}
			else{
				if (is_array($cron_found)){
					#remove postfix cron cmd
					$write_cron=1;
					}
				}
			#check if cron must be changed to Sqlite cmd
			if($cron_sqlite_queue != "" && $cron_sqlite_queue != "never"){
				$new_cron['item'][]=$cron_postfix_sqlite;
				$config['cron']=$new_cron;
				$write_cron=1;
				}
			}

			#call cron functions	
			if ($write_cron==1){
				$config['cron']=$new_cron;
				write_config('Postfix - sync remote sqlite database',$backup = false);
				configure_cron();
				}
			#remove postfix old cron call
			$old_cron=0;
			$crontab = file('/etc/crontab');
			$new_crontab="";
			foreach ($crontab as $line){
				if (preg_match("/php..usr.local.www.postfix_recipients.php/",$line))
					$old_cron=1;
				else
					$new_crontab .= $line;
				}
			if ($old_cron==1)	
				file_put_contents("/etc/crontab",$new_crontab, LOCK_EX);
		
			#print "
". var_dump($new_cron). var_dump($cron_postfix_sqlite).var_dump($config['cron']);
			#exit;
			
		
}
function sync_package_postfix($via_rpc="no") {
	global $config;
	
	log_error("sync_package_postfix called with via_rpc={$via_rpc}");
	# detect boot process
	if (is_array($_POST)){
		if (preg_match("/\w+/",$_POST['__csrf_magic']))
			unset($boot_process);
		else
			$boot_process="on";
	}
		
	if(is_process_running("master") && isset($boot_process) && $via_rpc=="no")
		return;
		
	#check patch in /etc/inc/config.
	$relay_domains = "";
	$transport = "";
	$postfix_config=$config['installedpackages']['postfix']['config'][0];
	if (is_array($config['installedpackages']['postfixdomains']))
		$postfix_domains=$config['installedpackages']['postfixdomains']['config'][0];
	$message_size_limit=($postfix_config['message_size_limit']?$postfix_config['message_size_limit']:"10240000");
	$process_limit=($postfix_config['process_limit']?$postfix_config['process_limit']:"100");
	if (is_array($postfix_domains['row'])) {
		foreach ($postfix_domains['row'] as $postfix_row) {
			$relay_domains .= ' ' . $postfix_row['domain'];
			if (!empty($postfix_row['mailserverip']))
				$transport .= $postfix_row['domain'] . " smtp:[" . $postfix_row['mailserverip'] . "]\n";
				}
			}
	#check cron
	check_cron();
	#check logging
	if ($postfix_config['log_to']){
			switch($postfix_config['log_to']){
				case 'maillog':
					system("/usr/bin/touch /var/log/maillog");
					$mail_syslog="mail.crit;";
				break;
				case 'none':
					$mail_syslog="mail.crit;";
				break;
				default:
					$mail_syslog='mail.*;';
				break;
			}
            #update /etc/inc/system.inc
            $sys_log_file='/etc/inc/system.inc';
            $pfsense_version=preg_replace("/\s/","",file_get_contents("/etc/version"));
            $sys_log = file($sys_log_file);
            $new_sys_log="";
            $found_mail=0;
            foreach ($sys_log as $line){
            	$new_line=preg_replace('/mail.(.|crit);/',$mail_syslog,$line);
            	if (preg_match('/mail.*system.log/',$line) && $postfix_config['log_to'] =="maillog"){
            		$new_sys_log .= 'mail.*'."\t\t\t\t\t\t".'/var/log/maillog'."\n";
            	}
            	if (preg_match('/maillog/',$line)){
            		$new_line ="";
            	}
            	$new_sys_log .= $new_line;
            }
            if (!file_exists('/root/'.$pfsense_version.'.system.inc.backup')) {
            	copy ($sys_log_file,'/root/'.$pfsense_version.'.system.inc.backup');
            }
            file_put_contents($sys_log_file,$new_sys_log, LOCK_EX);
            #mwexec('/usr/local/bin/php -q /usr/local/www/postfix_syslog.php');
            #restart syslog daemon	
            system_syslogd_start();
		}
           
	#check_debug
	if($postfix_config['debug_list'] && $postfix_config['debug_list']!=""){
	$check_debug ="\n#Debugging postfix\n";
	$check_debug.="debug_peer_list = ".px_text_area_decode($postfix_config['debug_list'])."\n";
	$check_debug.="debug_peer_level = ".$postfix_config['debug_level']."\n\n";
	}
	#check relay recipients
	$all_relay_recipients=sync_relay_recipients('gui');
	
	$copyright=<< $iface) {
	//	$real_ifaces[] = px_get_real_interface_address($iface);
	//	if($real_ifaces[$i][0]) {
	//		$postfix_master .=$real_ifaces[$i][0].":25	inet  n       -       n       -       1       postscreen\n\t-o user=postfix\n";
	$postfix_master = "smtp	inet  n       -       n       -       1       postscreen\n\t-o user=postfix\n";
	$postfix_master .=($antispam['soft_bounce'] == "postscreen"?"\t-o soft_bounce=yes\n":"");
	//	}
	//}
	$postfix_master .= $postfix_inets.<< $iface) {
		$real_ifaces[] = px_get_real_interface_address($iface);
		if($real_ifaces[$i][0]) {
			$postfix_master .=$real_ifaces[$i][0].":25	inet  n       -       n       -       -       smtpd\n";
		}
	}
	*/
	$postfix_master ="25	inet  n       -       n       -       -       smtpd\n";
		
	}
	$rbl2.=($rbl2 !=""?"\t\t\t\tpermit\n":"permit\n");
	$postfix_main=preg_replace("/RBLRBLRBL/",$rbl2,$postfix_main);
	
	#Header Maps
	$anvil_config=$config['installedpackages']['postfixantispam']['config'][0]['anvil'];
	if ($anvil_config =='enabled' || ($anvil_config =='postscreen' && $postscreen==1))
		$anvil='anvil     unix  -       -       n       -       1       anvil';
	
	$postfix_master .= << "postfix.sh", "start" => $start, "stop" => $stop));

	sleep(1);
	if (is_array($config['installedpackages']['postfix']) && $config['installedpackages']['postfix']['config'][0]['enable_postfix']){
		log_error("Reloading/starting postfix");
		system('/bin/chmod +x /usr/local/etc/rc.d/postfix.sh');
		mwexec_bg(POSTFIX_LOCALBASE."/sbin/postfix reload || /usr/local/etc/rc.d/postfix.sh start");
		log_error("Postfix setup completed");
		}
	else{
		log_error("Stopping postfix");
		mwexec("/usr/local/etc/rc.d/postfix.sh stop");
		system('/bin/chmod -x /usr/local/etc/rc.d/postfix.sh');
		}
		
	conf_mount_ro();
}

function postfix_validate_input($post, &$input_errors) {
	foreach ($post as $key => $value) {
		if (empty($value))
			continue;
		if($key == "greet_time" && !preg_match("/(\d+),(\d+)(s|m|h|w)/",$value))
				$input_errors[] = "Wrong greet time sintax.";			
		if($key == "message_size_limit" && !is_numeric($value))
				$input_errors[] = "Message size limit must be numeric.";
		if($key == "process_limit" && !is_numeric($value))
				$input_errors[] = "Process limit must be numeric.";	
		if($key == "freq" && (!preg_match("/^\d+(h|m|d)$/",$value) || $value == 0))
				$input_errors[] = "A valid number with a time reference is required for the field 'Frequency'";
		if (substr($key, 0, 2) == "dc" && !is_hostname($value))
				$input_errors[] = "{$value} is not a valid host name.";
		if (substr($key, 0, 6) == "domain" && is_numeric(substr($key, 6))) {
			if (!is_domain($value))
				$input_errors[] = "{$value} is not a valid domain name.";
		} else if (substr($key, 0, 12) == "mailserverip" && is_numeric(substr($key, 12))) {
			if (empty($post['domain' . substr($key, 12)]))
				$input_errors[] = "Domain for {$value} cannot be blank.";
			if (!is_ipaddr($value) && !is_hostname($value))
				$input_errors[] = "{$value} is not a valid IP address or host name.";
		}
	}
}

function postfix_php_install_command() {
	sync_package_postfix();
}

function postfix_php_deinstall_command() {
	global $config;
	#disable service
	if (is_array($config['installedpackages']['postfix']))
		$config['installedpackages']['postfix']['config'][0]['enable_postfix']="";
	write_config();
	sync_package_postfix();
	conf_mount_rw();
	unlink_if_exists("/usr/local/etc/rc.d/postfix.sh");
	conf_mount_ro();
}

/* Uses XMLRPC to synchronize the changes to a remote node */
function postfix_sync_on_changes() {
	global $config, $g;			
	if (is_array($config['installedpackages']['postfixsync']['config'])){
		$postfix_sync=$config['installedpackages']['postfixsync']['config'][0];
		$synctimeout = $postfix_sync['synctimeout'];
		$synconchanges = $postfix_sync['synconchanges'];
		switch ($synconchanges){
			case "manual":
				if (is_array($postfix_sync[row])){
					$rs=$postfix_sync[row];
					}
				else{
					log_error("[postfix] xmlrpc sync is enabled but there is no hosts to push postfix config.");
					return;
					}
				break;
			case "auto":
					if (is_array($config['installedpackages']['carpsettings']) && is_array($config['installedpackages']['carpsettings']['config'])){
						$system_carp=$config['installedpackages']['carpsettings']['config'][0];
						$rs[0]['ipaddress']=$system_carp['synchronizetoip'];
						$rs[0]['username']=$system_carp['username'];
						$rs[0]['password']=$system_carp['password'];
						$rs[0]['enabless']=true;
						$rs[0]['sync_type']="xmlrpc";
						if (! is_ipaddr($system_carp['synchronizetoip'])){
							log_error("[postfix] xmlrpc sync is enabled but there is no system backup hosts to push postfix config.");
							return;
							}
					}
					else{
						log_error("[postfix] xmlrpc sync is enabled but there is no system backup hosts to push postfix config.");
						return;
					}
				break;			
			default:
				return;
			break;
		}
		if (is_array($rs)){
			log_error("[postfix] xmlrpc sync is starting.");
			foreach($rs as $sh){
				$sync_to_ip = $sh['ipaddress'];
				if($sh['username'])
					$username = $sh['username'];
				else
					$username = 'admin';
				if($sh['password'] && $sh['ipaddress'] && $sh['enabless'])
					postfix_do_xmlrpc_sync($sh['ipaddress'], $username, $sh['password'],$sh['sync_type'],$synctimeout);
				}
			log_error("[postfix] xmlrpc sync is ending.");
			}
 		}
}


/* Do the actual XMLRPC sync */
function postfix_do_xmlrpc_sync($sync_to_ip,$username,$password,$sync_type,$synctimeout) {
	global $config, $g;

	if(!$username)
		$username="admin";
	
	if(!$password)
		return;

	if(!$sync_to_ip)
		return;
		
	if(!$synctimeout)
		$synctimeout=120;

	$xmlrpc_sync_neighbor = $sync_to_ip;
    if($config['system']['webgui']['protocol'] != "") {
		$synchronizetoip = $config['system']['webgui']['protocol'];
		$synchronizetoip .= "://";
    }
    $port = $config['system']['webgui']['port'];
    /* if port is empty lets rely on the protocol selection */
    if($port == "") {
		if($config['system']['webgui']['protocol'] == "http") 
			$port = "80";
		else 
			$port = "443";
    }
	$synchronizetoip .= $sync_to_ip;

	/* xml will hold the sections to sync */
	$xml = array();
	$sync_xml=$config['installedpackages']['postfixsync']['config'][0]['synconchanges'];
	$sync_db=$config['installedpackages']['postfixsync']['config'][0]['rsync'];
	if ($sync_xml && preg_match("/xmlrpc/",$sync_type)){
		log_error("Include postfix xmls");
		$xml['postfix'] = $config['installedpackages']['postfix'];
		$xml['postfixdomains'] = $config['installedpackages']['postfixdomains'];
		$xml['postfixacl'] = $config['installedpackages']['postfixacl'];
		$xml['postfixrecipients'] = $config['installedpackages']['postfixrecipients'];
		$xml['postfixantispam'] = $config['installedpackages']['postfixantispam'];
		}
	if (count($xml) > 0){
		/* assemble xmlrpc payload */
		$params = array(
			XML_RPC_encode($password),
			XML_RPC_encode($xml)
		);
	
		/* set a few variables needed for sync code borrowed from filter.inc */
		$url = $synchronizetoip;
		log_error("Beginning Postfix XMLRPC sync to {$url}:{$port}.");
		$method = 'pfsense.merge_installedpackages_section_xmlrpc';
		$msg = new XML_RPC_Message($method, $params);
		$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
		$cli->setCredentials($username, $password);
		if($g['debug'])
			$cli->setDebug(1);
		/* send our XMLRPC message and timeout after $sync_timeout seconds */
		$resp = $cli->send($msg, $synctimeout);
		if(!$resp) {
			$error = "A communications error occurred while attempting postfix XMLRPC sync with {$url}:{$port}.";
			log_error($error);
			file_notice("sync_settings", $error, "Postfix Settings Sync", "");
		} elseif($resp->faultCode()) {
			$cli->setDebug(1);
			$resp = $cli->send($msg, $synctimeout);
			$error = "An error code was received while attempting postfix XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
			log_error($error);
			file_notice("sync_settings", $error, "Postfix Settings Sync", "");
		} else {
			log_error("Postfix XMLRPC sync successfully completed with {$url}:{$port}.");
		}
		
		/* tell postfix to reload our settings on the destionation sync host. */
		$method = 'pfsense.exec_php';
		$execcmd  = "require_once('/usr/local/pkg/postfix.inc');\n";
		$execcmd .= "sync_package_postfix('yes');";
		
		/* assemble xmlrpc payload */
		$params = array(
			XML_RPC_encode($password),
			XML_RPC_encode($execcmd)
		);
	
		log_error("postfix XMLRPC reload data {$url}:{$port}.");
		$msg = new XML_RPC_Message($method, $params);
		$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
		$cli->setCredentials($username, $password);
		$resp = $cli->send($msg, $synctimeout);
		if(!$resp) {
			$error = "A communications error occurred while attempting postfix XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
			log_error($error);
			file_notice("sync_settings", $error, "postfix Settings Sync", "");
		} elseif($resp->faultCode()) {
			$cli->setDebug(1);
			$resp = $cli->send($msg, $synctimeout);
			$error = "An error code was received while attempting postfix XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
			log_error($error);
			file_notice("sync_settings", $error, "postfix Settings Sync", "");
		} else {
			log_error("postfix XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php).");
		}
	}
}

?>