Translate

Tuesday 2 July 2019


Filesystem quota on Roundcube (1.4)



To get “filesystem” quota working on Roundcube(1.4) Webmail we have to make few changes. If we have implemented filesystem quota on Squirrelmail or in any other webmail we will get it more easily.

Here this document we have used Postfix, Apache and Dovecot as IMAP service on CentOS 7.6. If you want to, you can choose any other IMAP service you can do so but you have to remember your IMAP should have this functionality à https://wiki2.dovecot.org/Quota/FS

Now There can be 2 cases:-

1. You have your user home directories on the same machine mounted as a local partition or SAN mounted.
For example:
Filesystem        Mounted on
/dev/sdax       /userhomedirs

In this case only configuring your Sudoers and Dovecot will do the job.

2. You have mounted your user home directories via NFS.
For example:
Filesystem                     Mounted on
10.0.1.xx:/userhomedirs      /userhomedirs

In this case along with Sudoers and Dovecot we have to modify functions of Roundcube also.

To implement filesystem quota on Roundcube we have to configure/modify three things.

1. Sudoers entry to run quota command.

2. Dovecot to activate the quota showing function in Roundcube.

3. Roundcube function modification to display the filesystem quota.

Let’s begin with sudoers:-

We will insert the following line at the very last of /etc/sudoers file

-------------------------------
apache ALL= PASSWD:ALL, NOPASSWD: /usr/bin/quota -v *, /bin/echo
-------------------------------

This will enable apache to run quota command as root, which will be very much needed.

Now Dovecot:-

In dovecot.conf we have to insert the following at proper places
-------------------------------

mail_plugins = " quota imap_quota"
##
## Plugin settings
##
plugin {
  quota = fs:User quota:user
}

-------------------------------

This will read the filesystem quota and forward it to Rouncube but it will not do so in case the user home directories are mounted as NFS. For that we have to modify Roundcube.

Now Roundcube:-

Go to the directory

# cd /var/www/html/webmail/program/lib/Roundcube

First we backup the default file

# cp –p rcube_imap_generic.php rcube_imap_generic.php-bak

Now open the file in any editor of your choice, here we use nano and search and replace the following function.

#nano rcube_imap_generic.php

Search for following function:-

-----------------------------------
public function getQuota($mailbox = null)
    {
        if ($mailbox === null || $mailbox === '') {
            $mailbox = 'INBOX';
        }

        // a0001 GETQUOTAROOT INBOX
        // * QUOTAROOT INBOX user/sample
        // * QUOTA user/sample (STORAGE 654 9765)
        // a0001 OK Completed

        list($code, $response) = $this->execute('GETQUOTAROOT', array($this->escape($mailbox)), 0, '/^\* QUOTA /i');

        $result   = false;
        $min_free = PHP_INT_MAX;
        $all      = array();

        if ($code == self::ERROR_OK) {
            foreach (explode("\n", $response) as $line) {
                list(, , $quota_root) = $this->tokenizeResponse($line, 3);

                $quotas = $this->tokenizeResponse($line, 1);

                if (empty($quotas)) {
                    continue;
                }

                foreach (array_chunk($quotas, 3) as $quota) {
                    list($type, $used, $total) = $quota;
                    $type = strtolower($type);

                    if ($type && $total) {
                        $all[$quota_root][$type]['used']  = intval($used);
                        $all[$quota_root][$type]['total'] = intval($total);
                    }
                }

                if (empty($all[$quota_root]['storage'])) {
                    continue;
                }
                 $used  = $all[$quota_root]['storage']['used'];
                $total = $all[$quota_root]['storage']['total'];
                $free  = $total - $used;

                // calculate lowest available space from all storage quotas
                if ($free < $min_free) {
                    $min_free          = $free;
                    $result['used']    = $used;
                    $result['total']   = $total;
                    $result['percent'] = min(100, round(($used/max(1,$total))*100));
                    $result['free']    = 100 - $result['percent'];
                }
            }
        }

        if (!empty($result)) {
            $result['all'] = $all;
        }

        return $result;
    }

-----------------------------------

And replace with this new modified function:-

-----------------------------------

public function getQuota($mailbox = null)
    {
        if ($mailbox === null || $mailbox === '') {
            $mailbox = 'INBOX';
        }

        $rcmail   = rcmail::get_instance();
        $user     = $rcmail->user;
        $usern    = rcube::Q($user->get_username());

        $result   = false;
        $min_free = PHP_INT_MAX;
        $all      = array();

                $used  = exec("/usr/bin/sudo /usr/bin/quota -v ". $usern . "| /usr/bin/tail -n 1 | /usr/bin/awk '{print $1}'");
                $total = exec("/usr/bin/sudo /usr/bin/quota -v ". $usern . "| /usr/bin/tail -n 1 | /usr/bin/awk '{print $2}'");
                $free  = $total - $used;

                // calculate lowest available space from all storage quotas
                if ($free < $min_free) {
                    $min_free          = $free;
                    $result['used']    = $used;
                    $result['total']   = $total;
                    $result['percent'] = min(100, round(($used/max(1,$total))*100));
                    $result['free']    = 100 - $result['percent'];
        }

        if (!empty($result)) {
            $result['all'] = $all;
        }

        return $result;
    }

--------------------------------

Basically we have to modify a function by which we will be able to see the filesystem/disk quota in the Roundcube Webmail.

If you are using earlier versions of Roundcube i.e. 1.3.9, you can take reference from this document as the file and function is same there are only few changes.

Now if you look closely

1. The sudoers modification was previously also necessary in squirrelmail or so, as it gives apache the authority to run quota command as root. Which was very much required to get info about user quota’s.

2. The dovecot (imap) modification is also needed as it enables dovecot to read the filesystem quota and pass it on. If you are familiar with “doveadm” we can also see quota through command line using doveadm, after this modification.
3. Roundcube is programmed in a way that it uses doveadm command to get quota from the system. So, here we have identified its function which is required to capture the user quota and modified it to run “quota” command. You have to note that in the modified function we have used the following lines:

------------------------
$used  = exec("/usr/bin/sudo /usr/bin/quota -v ". $usern . "| /usr/bin/tail -n 1 | /usr/bin/awk '{print $1}'");

$total = exec("/usr/bin/sudo /usr/bin/quota -v ". $usern . "| /usr/bin/tail -n 1 | /usr/bin/awk '{print $2}'");
-----------------------

Here we are doing nothing but in the variable we are inserting the filtered values which we get running the “quota” command. You must also notice that we are inserting the values of $1 and $2 in the variables, this might change to $2 and $3. You must run the command on a terminal for a user and can check what values $1 and $2 are carrying and you can modify accordingly.

If you want any help you can comment below or can mail me at: raiashish20 [at] gmail.com

Thursday 6 March 2014

HEARTBEAT (HA-CLUSTER) CONFIGURATION on LINUX

HEARTBEAT CONFIGURATION on LINUX

Below are the following steps which should be followed to setup HA-Cluster on two machine.

PREPARING THE SERVERS:-
We need to make sure that ntpd is configured and always running to keep both servers time synchronized.

# chkconfig ntpd on
HOSTNAME RESOLVE
Now let’s suppose we have created two servers :-

Host name                   ipaddress
Server1         test1                          10.2.1.231
Server2         test2                          10.2.1.232

Now we need to make sure that these two servers ping each also other with their hostname and for this we have to open

#nano /etc/hosts
And write these two lines in the file
10.2.1.231   test1
10.2.1.232   test2

Next try to ping both the servers from each other if they are able to ping then its fine otherwise you need to recheck the “/etc/hosts” file for your hostname.
Create the following file on both servers with the exact same content:

# nano /etc/ha.d/ha.cf
###################################################
logfile /var/log/ha-log
logfacility local0
keepalive 2
deadtime 30
initdead 120
bcast Auto_eth0
udpport 694
auto_failback on
node test1
node test2
###################################################

Note: Here in the above file we are broadcasting the service from Auto_eth0 “bcast Auto_eth0 “ . This will work when we have a single pair of machine that are running Heartbeat for High Availability, but it creates problems and gives error when there are multiple pairs of Heartbeat  running on the same subnet. To have multiple error-less  heartbeat running on the same subnet we need to do multicast instead of broadcast, so the “ha.cf” should look like this

# nano /etc/ha.d/ha.cf
###################################################
logfile /var/log/ha-log
logfacility local0
keepalive 2
deadtime 30
initdead 120
### here we are using mcast assigning the dev and class D multicast ip udp-port and ttl
mcast eth0 224.1.2.3 694 1 0
auto_failback on
node ldap1
node ldap2
###################################################
Note: The multicast ip should be same for a pair of systems and each pair in the environment should have their unique mcast ip so that they only synchronize by themselves and do not disturb other pairs.
The next step is to create the resource file for heartbeat on both servers with exact same content again:

# nano /etc/ha.d/haresources
test1 IPaddr::10.2.1.230/24/Auto_eth0  

first word is the hostname of the primary server then the IP 10.2.1.230 is the one I choose to be the virtual IP to be moved to the slave in case of a failure.
The last thing is to create the authentication file on both servers again with the same content:

# nano /etc/ha.d/authkeys
###################################################
auth 2
2 sha1 my-password
###################################################

This password file should only be readable by the root user:

# chmod 600 /etc/ha.d/authkeys

Ok now we should be ready to go… Let’s test it!!

On both servers start heartbeat service:

# service heartbeat start

Then check on server1

# ifconfig
*********************************************************
Auto_eth0 Link encap:Ethernet HWaddr 08:00:27:95:AB:B1
inet addr:10.2.1.230 Bcast:10.2.1.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe95:abb1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2189638 errors:0 dropped:0 overruns:0 frame:0
TX packets:30442386 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:188528923 (179.7 MiB) TX bytes:45853044392 (42.7 GiB)
Auto_eth0:0 Link encap:Ethernet HWaddr 08:00:27:95:AB:B1
inet addr:10.2.1.200 Bcast:10.2.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:305 errors:0 dropped:0 overruns:0 frame:0
TX packets:305 errors:0 dropped:0 overruns:0 carrier:0
*********************************************************

You can see that a new interface named Auto_eth0:0 can be seen which contained the virtual ip and as server 1 is the primary one it will be only on server 1 till the server is working or heartbeat is active. The ip will by self move to server2 in case when server 1 is inactive/crashed/heartbeat is stopped

Testing fail over
You can shut down server1 or simply stop heartbeat service:

On server1:

# service heartbeat stop

On server2:

# ifconfig
*********************************************************
Auto_eth0 Link encap:Ethernet HWaddr 08:00:27:8F:3B:50
inet addr:10.2.1.232 Bcast:10.2.1.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe8f:3b50/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:30447253 errors:0 dropped:0 overruns:0 frame:0
TX packets:2138369 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:45799991579 (42.6 GiB) TX bytes:173195698 (165.1 MiB)
Auto_eth0:0 Link encap:Ethernet HWaddr 08:00:27:8F:3B:50
inet addr:10.2.1.200 Bcast:10.0.4.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:208 errors:0 dropped:0 overruns:0 frame:0
TX packets:208 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
*********************************************************

Till this point if your machine responds in the same manner, congratulations you have now installed and configured DRBD with Heartbeat.

If you get any error refer to “/var/log/messages”.

Or be free to comment if any problem occurs.

Also I have tested that the heartbeat do not work good on OpenBSD as of security reason’s OpenBSD stores the mac address and when it system changes the virtual ip, the OpenBSD starts taking it as a threat and stops interacting with it.
However I am still trying so any comment is “WELCOME”

And the most important thing “Please try this at home” J
--

Ashish

Monday 21 October 2013

SETTING UP DYNAMIC DNS AND DHCP ON OPENBSD5.1



Setting Up DYNAMIC DNS and DHCP ON OPENBSD5.1

The purpose here is to create a DNS + DHCP machine where the DNS is Automatically updated according to the IP allocated by the DHCP.

For the following purpose first we have to install the ISC-DHCP and remove the default shipped DHCP, as it does not have the feature to implement the Automatic DNS updation. 

Package adding


Now replacing the executable
Run the following commands

#cd /sbin
#mkdir isc-dhcp-2.0
#mv dhclient isc-dhcp-2.0/
#mv dhclient-script isc-dhcp-2.0/
#mv /usr/local/sbin/dhclient-script dhclient-script
#mv /usr/local/sbin/dhclient dhclient
#cd /usr/sbin
#mkdir isc-dhcp-2.0
#mv dhcpd isc-dhcp-2.0/
#mv /usr/local/sbin/dhcpd dhcpd
#mv dhcrelay isc-dhcp-2.0/
#mv /usr/local/sbin/dhcrelay dhcrelay
#cd /usr/bin
#mv /usr/local/bin/omshell omshell
#cd /etc
#mkdir isc-dhcp-2.0
#mv dhclient.conf isc-dhcp-2.0/
#mv dhcpd.conf isc-dhcp-2.0/
#cp /usr/local/share/examples/isc-dhcp/dhclient.conf dhclient.conf
#cp /usr/local/share/examples/isc-dhcp/dhcpd.conf dhcpd.conf

Note:- If some some the above commands gives error like “no such file” or similar don’t panic just follow  and complete the process and if encountered any error, visit logs J.

Now generating the Key and copying it to /var/named/etc/rndc.key

#rndc-confgen

#less /etc/rndc.key
key "rndc-key" {
        algorithm hmac-md5;
        secret "4XS+kgobLMI3WmmLWgmMsQ==";
};

Copy the above key and then run

#cp /etc/rndc.key /var/named/etc/rndc.key

Configuring the dhcpd.conf

/etc/dhcpd.conf

####################START####################################
authoritative;              # No other DHCP servers on this subnet
ddns-update-style interim;  #Supported update method - see man
using ddns
ignore client-updates;      # Overwrite client configured FQHNs
ddns-domainname "example.com.";
ddns-rev-domainname "in-addr.arpa.";
allow unknown-clients;

###This is the key which we copied earlier, pasted here.

key "rndc-key" {
        algorithm hmac-md5;
        secret "4XS+kgobLMI3WmmLWgmMsQ==";
};

zone example.com. {          # Forward zone to be updated
    primary 127.0.0.1;
    key rndc-key;
 }

zone 8.168.192.in-addr.arpa. { # Backward zone to be updated
    primary 127.0.0.1;
    key rndc-key;
 }

option subnet-mask 255.255.255.0;

default-lease-time 172800;

max-lease-time 1209600;


shared-network example {
subnet 192.168.8.0 netmask 255.255.255.0 {
range 192.168.8.40 192.168.8.250;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.8.255;
option routers 192.168.8.1;
option domain-name "example.com";
option domain-name-servers 192.168.8.1;
}
}

#############################END##############################

Here the DHCP is configured for only single subnet hence one can increase the number of networks he/she wants to use according to his/her choice
Setting up DNS Server

The following “named.conf” consist only the two zone files which has to be updated according to the DHCP allotment, one can also have many other zone files which are static not to be updated dynamically and has different domain names according to his/her suitability.

Putting the following to the /var/named/etc/named.conf

========================START=================================
// $OpenBSD: named-simple.conf,v 1.10 2009/11/02 21:12:56 jakob Exp $
//
// Example file for a simple named configuration, processing both
// recursive and authoritative queries using one cache.


// Update this list to include only the networks for which you want
// to execute recursive queries. The default setting allows all hosts
// on any IPv4 networks for which the system has an interface, and
// the IPv6 localhost address.
//
acl clients {
     localnets;
     ::1;
};

options {
     version "";     // remove this to allow version queries

     listen-on    { any; };
     listen-on-v6 { any; };

     empty-zones-enable yes;

     allow-recursion { clients; };
};

logging {
     category lame-servers { null; };
};

// Standard zones
//
zone "." {
     type hint;
     file "etc/root.hint";
};

zone "localhost" {
     type master;
     file "standard/localhost";
     allow-transfer { localhost; };
};

zone "127.in-addr.arpa" {
     type master;
     file "standard/loopback";
     allow-transfer { localhost; };
};

zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" {
     type master;
     file "standard/loopback6.arpa";
     allow-transfer { localhost; };
};

###This is the key which we copied earlier also pasted here

key "rndc-key" {
        algorithm hmac-md5;
        secret "4XS+kgobLMI3WmmLWgmMsQ==";
};

zone " example.com" IN {
     type master;
           file "master/ example.com.zone";
           notify yes;
           allow-update { key "rndc-key";};
};

zone "8.168.192.in-addr.arpa" IN {
     type master;
        file "master/8.168.192.zone";
           notify yes;
        allow-update { key "rndc-key"; };
};

================================END============================

the following in /var/named/master/example.com.zone

========================START=================================
$ORIGIN .
$TTL 86400 ; 1 day
example.com       IN SOA     example.com. root. example.com. (
                     2013034708 ; serial
                     10800      ; refresh (3 hours)
                     3600       ; retry (1 hour)
                     604800     ; expire (1 week)
                     86400      ; minimum (1 day)
                     )
                NS   ns1.example.com.
$ORIGIN example.com.
$TTL 3600  ; 1 hour
================================END============================

the following in /var/named/master/8.168.192.zone

========================START=================================
ORIGIN .
$TTL 86400 ; 1 day
8.168.192.in-addr.arpa     IN SOA     example.com. root.example.com. (
                     2013032774 ; serial
                     10800      ; refresh (3 hours)
                     3600       ; retry (1 hour)
                     604800     ; expire (1 week)
                     86400      ; minimum (1 day)
                     )
                NS   ns1.example.com.
$ORIGIN 8.168.192.in-addr.arpa.
$TTL 3600  ; 1 hour
================================END============================

In the last changing the ownership of NAMED directory

#chown –R named:named /var/named/

And making dhcpd and named  run on start up

Open /etc/rc.conf and search

dhcpd_flags=NO
to
dhcpd_flags=""

and

named_flags=NO
to
named_flags=""