Table of Contents

Pure-FTPd with MySQL

This is how I setup my ftp server with Pure-FTPd and MySQL as backend for authentication and user profiles and sOLARiZ PureFTPd Manager as interface to MySQL.

Pure-FTPd Setup

Install Pure-FTPd the way you like it. As I use SuSE 9.3 I use the version bundled with the distribution and hence use the “SuSE Standard” for file locations.

Start out by editing the /etc/pure-ftpd/pure-ftpd.conf file to make use of MySQL as backend. Mine looks like this:

ChrootEveryone              yes
BrokenClientsCompatibility  no
MaxClientsNumber            10
Daemonize                   yes
MaxClientsPerIP             3
VerboseLog                  no
AllowDotFiles               yes
DisplayDotFiles             yes
AnonymousOnly               no
NoAnonymous                 yes
SyslogFacility              ftp
DontResolve                 yes
MaxIdleTime                 15
MySQLConfigFile               /etc/pure-ftpd/pureftpd-mysql.conf
LimitRecursion              2000 8
AnonymousCanCreateDirs      no
MaxLoad                     4
Umask                       177:077
MinUID                      100
AllowUserFXP                no
AllowAnonymousFXP           no
ProhibitDotFilesWrite       no
ProhibitDotFilesRead        no
AutoRename                  yes
AnonymousCantUpload         yes
NoChmod                     yes
CreateHomeDir               yes
MaxDiskUsage               99
NoRename                  yes
CustomerProof              yes

Lets create /etc/pure-ftpd/pureftpd-mysql.conf:

MYSQLServer     localhost
MYSQLPort       3306
MYSQLUser       ftpd
MYSQLPassword   123456
MYSQLDatabase   System
MYSQLCrypt      md5
MYSQLGetPW      SELECT Password FROM ftpd WHERE User="\L" AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MYSQLGetUID     SELECT Uid FROM ftpd WHERE User="\L" AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MYSQLGetGID     SELECT Gid FROM ftpd WHERE User="\L"AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MYSQLGetDir     SELECT Dir FROM ftpd WHERE User="\L"AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MySQLGetBandwidthUL SELECT ULBandwidth FROM ftpd WHERE User="\L"AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MySQLGetBandwidthDL SELECT DLBandwidth FROM ftpd WHERE User="\L"AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MySQLGetQTASZ   SELECT QuotaSize FROM ftpd WHERE User="\L"AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")
MySQLGetQTAFS   SELECT QuotaFiles FROM ftpd WHERE User="\L"AND status="1" AND (ipaccess = "*" OR ipaccess LIKE "\R")

MySQL

Install MySQL on a server or use a already installed one. Again I use the one following SuSE 9.3.

I use a thirdparty PHP interface to the MySQL database called sOLARiZ PureFTPd Manager, so I also have Apache2 with PHP and PHP-mysql installed. You can also download it here pureftp-mgr.tar

You can configure the MySQL database in many ways and make use of a lot of Pure-FTPd's features, but as I'm using PureFTPd Manager I'm bound to its design.

Create a database:

# mysqladmin -u root -p create System

Next make the following file called create.sql:

 DROP TABLE IF EXISTS ftpd;
                CREATE TABLE ftpd (
                User varchar(16) NOT NULL default '',
                status enum('0','1') NOT NULL default '0',
                Password varchar(64) NOT NULL default '',
                Uid varchar(11) NOT NULL default '-1',
                Gid varchar(11) NOT NULL default '-1',
                Dir varchar(128) NOT NULL default '',
                ULBandwidth smallint(5) NOT NULL default '0',
                DLBandwidth smallint(5) NOT NULL default '0',
                comment tinytext NOT NULL,
                ipaccess varchar(15) NOT NULL default '*',
                QuotaSize smallint(5) NOT NULL default '0',
                QuotaFiles int(11) NOT NULL default 0,
                PRIMARY KEY (User),
                UNIQUE KEY User (User)
                ) TYPE=MyISAM;

Use this file to create the our user table:

# mysql -u root -p System < create.sql

Use this file, create-user.sql, to create the ftpd user and its rights:

USE mysql;
INSERT INTO user (Host, User, Password) VALUES ('localhost','ftpd',password('123456'));
INSERT INTO db (Host, Db, User, Select_priv, Insert_priv, Update_priv, Delete_priv) VALUES ('localhost', 'System', 'ftpd', 'Y', 'Y', 'Y', 'Y');
FLUSH PRIVILEGES;
GRANT SELECT, INSERT, DELETE, UPDATE ON System.* TO ftpd@localhost;

Now run it:

# mysql -u root -p -h localhost < create-ftpd.sql

Apache2

Now copy the sOLARiZ PureFTPd Manager files into your documentroot somewhere. As we are dealing with usernames and passwords I like to use https. With SuSE 9.3 the tool gensslcert will make the certificate for you. If you aren't using SuSE, look at the manpages for openssl. To make use of this I have created /etc/apache2/vhosts.d/pureftpd.conf:

Listen 666
<VirtualHost _default_:666>
DocumentRoot "/srv/www/htdocs/pureftpd"
ServerName localhost:666
ServerAdmin you@example.com
ErrorLog /var/log/apache2/pureftpd_error_log
TransferLog /var/log/apache2/pureftpd_access_log
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /etc/apache2/ssl.crt/server.crt
SSLCertificateKeyFile /etc/apache2/ssl.key/server.key
<Directory "/srv/www/htdocs/pureftpd">
    SSLOptions +StdEnvVars
    SSLRequireSSL
</Directory>
SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog /var/log/apache2/postfixadmin_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
<Directory /srv/www/htdocs/pureftpd>
    AllowOverride AuthConfig
    Order deny,allow
    Allow from all
</Directory>
</VirtualHost>

This creates an https webinterface listening on port 666/tcp. To enter this interface you browse to https://yourserver:666

I would like to be the only one accessing this interface and therfor we need some authentication. Create .htaccess in the documentroot /srv/www/htdocs/pureftpd/:

AuthUserFile /srv/www/htdocs/pureftpd/.htpasswd
AuthGroupFile /dev/null
AuthName "Pure-ftpd Admin"
AuthType Basic

<limit GET POST>
require valid-user
</limit>

Create the htpasswd file and create a admin user:

# htpasswd2 -c /srv/www/htdocs/pureftpd/.htpasswd admin

PureFTPd Manager

Create a user and group called “pureftpd”.

Extract the PureFTPd Manager files into “/srv/www/htdocs/pureftpd”.

To make use of md5 instead of crypt I changed “index.php” to:

<?
// Aenderungen 25.5. Uwe Ahrendt
// www.bildpartner.de

// READ THE README !!!
/****************************************************
 * PureFTP - PHP USer Manager by solariz
 * Source (c) 2002 - www.solariz.de
 ****************************************************
 CheckOut:  http://www.solariz.de
*/

include("pureftp.config.php");

#################################################################
############### NO NEED FOR CHANGES BELOW HERE ##################
#################################################################
// Config einlesen
        if(!file_exists($PUREFTP_CONFIG_FILE)) DIE("FATAL ERROR: Pure FTPD Config file not found.<br />$PUREFTP_CONFIG_FILE");
        $USERARRAY = array();
        $raw = file($PUREFTP_CONFIG_FILE);
        foreach($raw AS $zeile):
                if(!ereg("^#",$zeile)): #skip comments
                        // Einlesen der einzelnen Zeilen als Variable
                                $tmp = split(" ",trim($zeile));
                                // UNIX Tab workaround
                                if(count($tmp) < 2)
                                        $tmp = explode("\t",trim($zeile));
                                $var = strtoupper(trim($tmp[0]));
                                for($n=1;$n<count($tmp);++$n) {
                                        if(!empty($tmp[$n])) {
                                                $$var = trim($tmp[$n]);
                                                break;
                                        }#end if
                                }#end for
                        // Einlesen der Tabelle
                                if(empty($DB_TABLE) AND eregi("FROM\ [[:alnum:]]{1,20}\ WHERE",$zeile)):
                                        $tmp2 = split("FROM ",$zeile);
                                        $tmp2 = split(" WHERE",trim($tmp2[1]));
                                        $DB_TABLE = trim($tmp2[0]);
                                        unset($tmp2);
                                EndIF;
                EndIf;
        EndForEach;
        if(empty($MYSQLSERVER)) $MYSQLSERVER = "localhost";
        if(empty($DB_TABLE))    DIE("ERROR: Config error in pureftpd config file. No table specified.");
// UA
        if ($MYSQLCRYPT == "md5") {$PW = TRUE;} else {$PW = FALSE;}

// Current Version
        $VERSION = "2.50";
        $BUILD          = "1018";

// Setein header
        PAGE_HEADER();

// SQL Connection herstellen
        DB_OPEN();


// FORM SUBIT AUSWERTUNG // Globals
        $action         = get_var("action");
        $user           = get_var("user");

if( $action == "edit" || $action == "add" ) {
        // ADD value setter

                if($action == "add"):
                                $USERARRAY['User']              = $DefaultUser;
// UA
                                if ($PW) {$USERARRAY['Password']        = md5($DefaultPass); }
                                        else {$USERARRAY['Password']    = $DefaultPass; }
                                $USERARRAY['Password']  = $DefaultPass;
                                $USERARRAY['Uid']               = $DefaultUid;
                                $USERARRAY['Gid']               = $DefaultGid;
                                $USERARRAY['Dir']               = $DefaultDir;
                                $USERARRAY['ULBandwidth']       = $DefaultUL;
                                $USERARRAY['DLBandwidth']       = $DefaultDL;
                                $USERARRAY['ipaccess']  = $Defaultip;
                                $USERARRAY['QuotaSize'] = $DefaultQS;
// UA
                                $USERARRAY['QuotaFiles']        = $DefaultQF;
        $USERARRAY['comment']        = $Defaultcmt;
                                else:
                                unset($USERARRAY);
                EndIf;

                if(!empty($user) AND $user != "0") {
                                $USERARRAY=@MYSQL_FETCH_ARRAY(DB_QUERY("SELECT * FROM `$DB_TABLE` WHERE User LIKE '$user'"));
                }#end if
                if(!is_array($USERARRAY)) DIE("User Not found or DB error.<br />".mysql_error());

        echo '<form method=post action="'.$SELF_URL.'" onSubmit="return checkrequired(this)">';

        if(!empty($user))       echo '<input type="hidden" name="requireduser" value="'.stripslashes($USERARRAY['User']).'">';
        else                                            echo '<input type="hidden" name="addnew" value="True">';
        echo '<input type="hidden" name="action" value="save">';
        echo '<table width="100%" class=TABLE>';
        echo '<tr><th>Status</th><td class=TD><input type="radio" name="status" value="0"';
        if($USERARRAY['status'] == 0) echo ' checked';
        echo '> Inactive&nbsp;&nbsp;&nbsp;<input type="radio" name="status" value="1"';
        if($USERARRAY['status'] == 1) echo ' checked';
        echo '> Active</td></tr>';

        if(!empty($user))       {
                echo '<tr><th>Delete user ?</th><td class=TD><input type="checkbox" name="delete"> Yes, i am know exactly what i am doing! (NO UNDO)</td></tr>';
                echo '<tr><th>Username</th><td class=TD>'.stripslashes($USERARRAY['User']).'</td></tr>';
        }

        else

        echo '<tr><th>Username</th><td class=TD><input type="text" name="requireduser" class="input"></td></tr>';
        echo '<tr>';
        echo '<th>Password</th>';
// UA
        if ($PW) {
                echo '<td class=TD><input type="text" name="requiredpass" value="<crypted>" class="input"></td></tr>';
        } else {
                echo '<td class=TD><input type="text" name="requiredpass" value="'.stripslashes($USERARRAY['Password']).'" class="input"></td></tr>';
        }
        echo '<tr><th>UID</th><td class=TD><input type="text" name="requireduid" value="'.stripslashes($USERARRAY['Uid']).'" class="input"></td></tr>';
        echo '<tr><th>GID</th><td class=TD><input type="text" name="requiredgid" value="'.stripslashes($USERARRAY['Gid']).'" class="input"></td></tr>';
        echo '<tr><th>DIR</th><td class=TD><input type="text" name="requireddir" value="'.stripslashes($USERARRAY['Dir']).'" class="input"></td></tr>';
    echo '<tr><th>UL Throttle kb/s</th><td class=TD><input type="text" name="requiredulthrottle" value="'.stripslashes($USERARRAY['ULBandwidth']).'" class="input"></td></tr>';
    echo '<tr><th>DL Throttle kb/s</th><td class=TD><input type="text" name="requireddlthrottle" value="'.stripslashes($USERARRAY['DLBandwidth']).'" class="input"></td></tr>';
        echo '<tr><th>IP ACCESS</th><td class=TD><input type="text" name="requiredipaccess" value="'.stripslashes($USERARRAY['ipaccess']).'" class="input"><br /><small>Type in <b>*</b> for any IP</td></tr>';
// UA
        echo '<tr><th>QuotaSize in MB</th><td class=TD><input type="text" name="requiredQuotaSize" value="'.stripslashes($USERARRAY['QuotaSize']).'" class="input"><br /><small>Type in <b>0</b> for NO VirtualQuotaSize</td></tr>';
// UA
        echo '<tr><th>QuotaFiles Anzahl</th><td class=TD><input type="text" name="requiredQuotaFiles" value="'.stripslashes($USERARRAY['QuotaFiles']).'" class="input"><br /><small>Type in <b>0</b> for NO VirtualQuotaFiles</td></tr>';
        echo '<tr><th>COMMENT</th><td class=TD><textarea name="comment" rows="6" cols="20" class="input">'.stripslashes($USERARRAY['comment']).'</textarea></td></tr>';
        echo '</table>';
        echo '<center><input type="submit" value="Save" class="button" width="100%"></center></form>';

}#end edit

elseif($action == "save") {
        $addnew         = addslashes( get_var("addnew") );
        $User           = addslashes(get_var("requireduser"));

        // UA - MG Optimized ;)
        $Password = addslashes(get_var("requiredpass"));

        IF($Password == '<crypted>')    $Password = '';
        ELSEif($PW)                                             $Password = md5($Password);

        $Uid            = addslashes(get_var("requireduid"));
        $Gid            = addslashes(get_var("requiredgid"));
        $Dir            = addslashes(get_var("requireddir"));
    $ULThrottle        = addslashes(get_var("requiredulthrottle"));
    $DLThrottle        = addslashes(get_var("requireddlthrottle"));
        $QuotaSize      = addslashes(get_var("requiredQuotaSize"));
// UA
        $QuotaFiles     = addslashes(get_var("requiredQuotaFiles"));
        $comment        = addslashes(get_var("comment"));
        $status         = addslashes(get_var("status"));
        $delete         = addslashes(get_var("delete"));
        $ipaccess   = addslashes(get_var("requiredipaccess"));
        if(empty($User) ||  empty($Uid) || empty($Gid) || empty($Dir)) DIE("Invalid or missing data entered...");
        if(empty($delete)) {
                // Mini workarounds
                        if($Password)   $PW_QUERY = ",Password='$Password'";
                        if(!$status)            $status = (string) '0';
                        if(!$ULBandwidth)       $ULBandwidth = (string) '0';
                        if(!$DLBandwidth)       $DLBandwidth = (string) '0';
                        if(!$QuotaSize)         $QuotaSize = (string) '0';
                        if(!$QuotaFiles)        $QuotaFiles = (string) '0';
                if($addnew == False) {
                        $SQL    = "UPDATE `$DB_TABLE` SET status='$status'".$PW_QUERY.",Uid='$Uid',Gid='$Gid',Dir='$Dir',ULBandwidth='$ULThrottle',DLBandwidth='$DLThrottle',comment='$comment',ipaccess='$ipaccess',QuotaSize='$QuotaSize',QuotaFiles='$QuotaFiles' WHERE User LIKE '$User' LIMIT 1";
                        $Q              = DB_QUERY($SQL);
                        if($Q)  echo "<SCRIPT LANGUAGE=\"JavaScript\">\n<!--\nalert(\"User updated.\");\n//-->\n</SCRIPT>\n";
                }#end if
                else{
                        $Q              = DB_QUERY("INSERT INTO `$DB_TABLE` SET User='$User',status='$status'".$PW_QUERY.",Uid='$Uid',Gid='$Gid',Dir='$Dir',ULBandwidth='$ULThrottle',DLBandwidth='$DLThrottle',comment='$comment',ipaccess='$ipaccess',QuotaSize='$QuotaSize',QuotaFiles='$QuotaFiles'");
                        if($Q)  echo "<SCRIPT LANGUAGE=\"JavaScript\">\n<!--\nalert(\"User added.\");\n//-->\n</SCRIPT>\n";
                }#end if

        }#end if
        elseif($User && !empty($delete)){#DELETE
                        $Q              = DB_QUERY("DELETE FROM `$DB_TABLE` WHERE User LIKE '$User' LIMIT 1");
                        if($Q)  echo "<SCRIPT LANGUAGE=\"JavaScript\">\n<!--\nalert(\"User deleted.\");\n//-->\n</SCRIPT>\n";
        }#end if
        echo "<SCRIPT LANGUAGE=\"JavaScript\">\n<!--\nopener.location.reload();close();\n//-->\n</SCRIPT>\n";
}#end else (save)

######
elseif($action == "ftpwho") {

echo '<table border="4">';
 exec($FTP_WHO." -s", $ftpresult );
 $arraySize = sizeof($ftpresult);
 $x = 0;
echo '<table width="100%" class=TABLE>';
echo '<th class=THsmall>PID</td>';
echo '<th class=THsmall>user</td>';
echo '<th class=THsmall>min\'s</td>';
echo '<th class=THsmall>state</td>';
echo '<th class=THsmall>file</td>';
echo '<th class=THsmall>IP</td>';
echo '<th class=THsmall>current</td>';
echo '<th class=THsmall>total</td>';
echo '<th class=THsmall>%</td>';
echo '<th class=THsmall>bw.</td>';
while($x < $arraySize):
         $ftpwho = $ftpresult[$x];
         list($pid, $user, $mins, $state, $file, $host, $port,$h, $current, $total, $percent, $bandwidth ) = explode("|", $ftpwho );
         $mins = round($mins / 60);
         if (empty($file) or !isset($file)) {
                 ( $file = "---" );
                 ++$ftp_activity;
         }
         else {
                if(strlen($file) > 10)
                        $file_short = substr($file,0,10);
                        $file = "<a href=\"#\" onClick=\"javascript:alert('$file');\">$file_short...</a>";
         }#end else
         $host = gethostbyname($host);
                echo '<tr>';
                echo '<td class=TDsmall>' .$pid. '</td>';
                echo '<td class=TDsmall>' .$user. '</td>';
                echo '<td class=TDsmall>' .$mins. '</td>';
                echo '<td class=TDsmall>' .$state. '</td>';
                echo '<td class=TDsmall>' .$file. '</td>';
                echo '<td class=TDsmall>' .$host. '</td>';
                echo '<td class=TDsmall>' .$current. '</td>';
                echo '<td class=TDsmall>' .$total. '</td>';
                echo '<td class=TDsmall>' .$percent. '</td>';
                echo '<td class=TDsmall>' .$bandwidth. ' kb/s</td>';
                echo '</tr>';
          $x++;
EndWhile;
echo '</table>';
if(!$ftp_activity) echo 'No users currenty using the FTP.<br>';

echo '<p><center><input type=button value=" Close " onclick=self.close()>';
echo '<input type=button value=" Refresh " onClick=" JavaScript : window.location.reload()"></center>';


}#end else (ftpwho)
######
elseif($action == "info") {
?>
        <font color=gray face="Verdana,Arial">
        <b>sOLARiZ PureFTPd Manager</b><br>
        Version <?=$VERSION?> Build <?=$BUILD?><br><br>
        About
        <ul class="small_font">
          The first version of this Script was developed roughly at the end of 2001 in need of a simplyfied remote FTP administration. Since this many user submited changes / updates were integrated. If you got special wishes please let me know via mail.<br>
          One thing to note; I don't take any guarantee either I'm not liable for possible caused damage. This script is free no need to pay for it. But if you like it im be glad for a donation. Everything is welcome e.g. a PayPAL donation:<br>
          <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
          <input type="hidden" name="cmd" value="_xclick">
          <input type="hidden" name="business" value="paypal@solariz.de">
          <input type="hidden" name="item_name" value="PureFTPd Manager Donation">
          <input type="hidden" name="no_note" value="1">
          <input type="hidden" name="currency_code" value="EUR">
          <input type="hidden" name="tax" value="0">
          <input type="image" src="http://www.solariz.de/x-click-but04.gif" border="0" name="submit" alt="Zahlen Sie mit PayPal - schnell, kostenlos und sicher!">
          </form>
          <br>
          For Information or other stuff regarding pureFTPd Manager or other scripts please visit <a href="http://www.solariz.de" target=_blank>www.solariz.de</a>
        </ul>
              ChangeLog
                                <ul class="small_font">
                                <?
                                        $raw = file("history.txt");
                                        foreach($raw AS $hline):
                                                        echo stripslashes($hline)."<br>\n";
                                        EndForEach;
                                ?>
                                </ul>

<?
}
ELSE {
// User auslesen und in Table darstellen
        $viewpw = get_var("viewpw");
        $Q=DB_QUERY("SELECT * FROM `$DB_TABLE` ORDER BY User");
        echo '<table width="100%" class=TABLE>';
        echo '<tr><th>LOGIN</th>';
        if($viewpw) echo '<th>PASSWORD</th>';
// UA
        echo '<th>UID</th><th>GID</th><th>DIR</th><th>UL/ks</th><th>DL/ks</th><th>Quota Size</th><th>Quota Files</th><th>IP Access</th><th>Status</th><th>&nbsp;</th></tr>';
        WHILE($R=MYSQL_FETCH_ARRAY($Q)) {
                echo '<tr>';
                echo '<td class=TD>'.$R['User'].'</td>';
                if($viewpw) echo '<td class=TDPW>'.$R['Password'].'</td>';
                echo '<td class=TD>'.$R['Uid'].'</td>';
                echo '<td class=TD>'.$R['Gid'].'</td>';
                echo '<td class=TD>'.$R['Dir'].'</td>';
                if($R['ULBandwidth'])   echo '<td class=TD>'.$R['ULBandwidth'].'</td>';
                ELSE                                                            echo '<td class=TD>-</td>';
                if($R['DLBandwidth'])   echo '<td class=TD>'.$R['DLBandwidth'].'</td>';
                ELSE                                                            echo '<td class=TD>-</td>';
                if($R['QuotaSize'])     echo '<td class=TD>'.$R['QuotaSize'].' MB</td>';
                ELSE                                                    echo '<td class=TD>-</td>';
// UA
                if($R['QuotaFiles'])    echo '<td class=TD>'.$R['QuotaFiles'].'</td>';
                ELSE                                                    echo '<td class=TD>-</td>';
                echo '<td class=TD>'.$R['ipaccess'].'</td>';
                if($R['status'] == '0')         echo '<td class="inactive">inactive</td>';
                elseif($R['status'] == '1')     echo '<td class="active">active</td>';
                echo "<td width=30 class=TD><img src=\"gfx/ed.gif\" onClick=\"javascript:fenster('$SELF_URL?action=edit&user=".$R['User']."')\"></td>";

                echo "</tr>\n";
        }#end while
        echo '</table>';
        ?>
                <table width="100%" class=TABLE2>
                        <tr>
                                <td align=left>
        <font color=gray>
                                        PureFTP User Management.<br />
                                        v<?=$VERSION?> written by sOLARiZ <br />
                                        [<a href="javascript:fenster('<?=$SELF_URL?>?action=info')"><font color=#BA031B size=1>Information</font></a>]<br />
                                </td>
                                <td>&nbsp;</td>
                                <td align=right valign=top>
        <?
        // Nav Button stuff
                echo "<table cellspacing=0 cellpadding=0><tr>";
                // Add User Button
                                ECHO "<td><input type=\"image\" src=\"gfx/addusr.gif\" class=button onClick=\"javascript:fenster('$SELF_URL?action=add')\"></td>";
                // View Password Button
                                echo '<form method=post action="'.$PHP_SELF.'">';
                                if($viewpw)     echo '<input type="hidden" value=0 name="viewpw">';
                                ELSE                            echo '<input type="hidden" value=1 name="viewpw">';
                                ECHO '<td><input type="image" src="gfx/passwd.gif" value="View Passwords" alt="Toggle Passworddisplay"';
                                if(!$viewpw) echo ' class=button';
                                ECHO '></td>';
                                echo '</form>';
                // Status Button
                                ECHO "<td><input type=\"image\" src=\"gfx/status.gif\" class=button onClick=\"javascript:fenster('$SELF_URL?action=ftpwho')\"></td>";
                // Update Button
                                ECHO "<td><input type=\"image\" src=\"gfx/updates.gif\" class=button onClick=\"javascript:fenster('http://www.solariz.de/updates/pureftpdm.php?ver=$VERSION&ab=$BUILD')\"></td>";
                echo "</tr></table>";
########

        echo '</td></tr></table>';
}#end else

// SQL Verbindung schliessen
        DB_CLOSE();


// Seite abschliessen
PAGE_FOOTER();







// EOC <--*







// Funktionen

        function PAGE_HEADER() {
    GLOBAL $VERSION, $BUILD;
    include("inc/top.php");
  }#end func

        function PAGE_FOOTER() {
      include("inc/bottom.php");
  }#end func

        function DB_OPEN() {
                GLOBAL $MYSQLSERVER,$MYSQLUSER,$MYSQLPASSWORD,$MYSQLDATABASE,$MYSQLCON;
                        $MYSQLCON = @mysql_connect($MYSQLSERVER,$MYSQLUSER,$MYSQLPASSWORD);
                        if(!$MYSQLCON OR @mysql_error()) DIE("Can't establish DB connection.<br />".mysql_error());
                        if(!@mysql_select_Db($MYSQLDATABASE)) DIE("Can't establish DB connection.<br />".mysql_error());
        }#end func

        function DB_CLOSE() {
                GLOBAL $MYSQLCON;
                RETURN @mysql_close($MYSQLCON);
        }#end func

        function DB_QUERY($sql) {
                GLOBAL $MYSQLCON,$MYSQLDATABASE;
                $Q = @MySql_DB_query($MYSQLDATABASE,$sql,$MYSQLCON);
                if(@mysql_error()) DIE("<b>MySQL Error during Query !</b><br /><br />[$sql]<br />".mysql_error());
                return $Q;
        }#end func

        function get_var($var){
                GLOBAL $$var;
                GLOBAL $_POST,$_GET,$HTTP_POST_VAR,$HTTP_GET_VAR;
                $inhalt = $$var;
                # This function checks if the _GET or _POST var is set or if an old PHP version used
                if($_POST[$var]) RETURN $_POST[$var];
                elseif($HTTP_POST_VAR[$var]) RETURN $HTTP_POST_VAR[$var];
                elseif($_GET[$var]) RETURN $_GET[$var];
                elseif($HTTP_GET_VAR[$var]) RETURN $HTTP_GET_VAR[$var];
                elseif($inhalt) RETURN $inhalt;
        }#end func
?>

My “pureftp.config.php” looks like this:

<?php
######################
####### SETUP ########
######################

        // Your exactly located mysql config file for pureftpd
        $PUREFTP_CONFIG_FILE    = '/etc/pure-ftpd/pureftpd-mysql.conf';

        // The location where all the Forms directed to. (Mayby no change needed)
        $SELF_URL                               = '/index.php';

        // The location of your pure-ftpdwho binary  (set this to chmod 4711)
        $FTP_WHO                                = "/usr/sbin/pure-ftpwho";

#######################
# DEFAULT NEW-USER PARAMS #
#######################

        $DefaultUser = "";              # Default User Logon
        $DefaultPass = "";                          # Default User Password
        $DefaultUid = "pureftpd";                       # Default User ID ( must be a real user acct )
        $DefaultGid = "pureftpd";                 # Default Group ID ( must be a real group acct )
        $DefaultDir = "/srv/ftp/";                                  # Default User Dir ( use /./ at the end to chroot )
        $DefaultUL = "0";                                   # Default Upload Throttle ( 0 disables it )
        $DefaultDL = "0";                                   # Default Download Throttle ( 0 disables it )
        $Defaultip = "*";                                   # Default IP restrictions  ( * = any IP )
        $DefaultQS = "0";                             # Default Quota Size ( 0 disables it )
        $Defaultcmt = "";                                   # Default Comment for user

// UA
        $DefaultQF = "0";                       # Default Quota Files ( 0 disables it )
        $PWC = "55";                              # Vorsatz fuerr Crypt Password
?>

This is basically it. Point your browser at https://yourwebserver:666//, login and start sharing diskspace :-P
An alternate Pure-Ftpd GUI can be found at http://machiel.generaal.net/index.php?subject=user_manager_pureftpd.