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

No comments:

Post a Comment