Rootless glftpd
Glftpd by default runs as root. It's launched as root, and it will never give up the root privilege. It uses a function named seteuid(uid); to escalate between privileges.
This is an artifact from the original way that glftpd accounted for ownership and stats by using the UNIX ACLs to see who owns a file. This also means that in order to delete some other user's file, or to write to a root owned log file, you will need to escalate to root. Glftpd will do this temporarily but seteuid(0); and when done switch back to your regular uid defined in /etc/passwd.
Even though you in ps -ef see glftpd run as a regular user, it must have privileges to escalate in order to function.
What this means for you is that anyone hacking glftpd, nomatter if this is done while your UID is currently a user or root, can most likely inject shell code which can trigger seteuid(0);, and your system is compromised.
Warning!
The binaries built with these capabilities are only a technical preview. The SQLite3 implementation is not perfect in regards to locking and transaction. The SQLite3 implementation is open sourced, and can be found here. Your contributions are welcomed!
If you are a DB junkie or have a good model for implementation for access, please contribute. If you are a script maintainer which rely on the filesystem ownership (st_uid/st_gid), please implement support for reading the .ownerdb files.
Current implementation design
As the rootless glftpd cannot rely on the filesystem ACLs for ownership, we need to implement another separate structure. We used SQLite3 for this not having to reinvent the wheel. As SQLite3 is an atomic accounting database with slim traces and open license.
We use one micro db per folder which glftpd manages. This is to reduce locking issues (one central DB would introduce longer waits for locks) and to make transparency to external tools as slim as possible. For instance, if you move a directory to your Archive disk, you would need to update a central DB in order to keep permissions. But with this approach the permissions follow the directory automaticly.
Glftpd will maintain and create/delete the owner database files as a part of the regular use. It's integrated in the MKD / DELE / RMD commands, and doing RETR/STOR will update the database accordingly.
The filename for the owner database is .ownerdb. The structure for the file is:
CREATE TABLE files (
fn TEXT PRIMARY KEY, # Filename
un TEXT, # Username
gn TEXT, # Groupname
uid INT, # UserID (st_uid)
gid INT, # GroupID (st_gid)
dn INT # Download count
);
Activation in glftpd
Now that you have hopefully read and understood what this implies, here comes the options which enables you to use a non-rooted glftpd.
glftpd.conf
ownerdb 1
- Activates the code invoking creation / deletion / maintaining of the .ownerdb files. This can be enabled to passively create these files.
ownerdb_invoke 1
- Invokes reading ownership in all aspects from .ownerdb. Also enables glftpd to drop permanent root privileges.
glftpd_user <uid> <gid>
- Numeric values to set the user which glftpd will drop to. To get the numeric values, run "id <username>"! Failure to specify will make glftpd run as 99:99.
Other recommendations:
hidden_files / .ownerdb .ownerdb-shm .ownerdb-wal
- Append your hidden_files with all files which can be created by the DB process.
noretrieve .ownerdb .ownerdb-shm .ownerdb-wal
- Append your noretrieve with all files which can be created by the DB process.
Permissions
As glftpd will run as this single UID user, this UID will need permission to read/write files under your glftpd chroot (for instance /glftpd or /jail/glftpd). Modify permissions accordingly. Recommended permissions read/write:
$GLROOT/ftp-data/* (for logs, oneliners, messages, etc)
$GLROOT/tmp (for external scripts)
$GLROOT/site (obviously, how else to put files? :)
If you have the possibility you can always chown -R uid:gid $GLROOT, this will however wipe your current file ACLs for existing structure. Beware.
SHMs
Glftpd uses Shared Memory Segments to exchange information inbetween processes and to external processes (sitewho and gl_spy are two examples). Because of this, make sure to killall glftpd and to ipcrm all shared memory segments related to glftpd as displayed in ipcs.
If in doubt, refer to the glftpd.docs on this. It is the same procedure as increasing max_users.
A correct SHM memory segment will look like:
------ Shared Memory Segments --------
key shmid owner perms bytes nattch
0x0000dead 884736 gl_user 644 18080 0
0x0000deae 786433 gl_user 644 2101252 0
------ Semaphore Arrays --------
key semid owner perms nsems
0x0000dead 655360 gl_user 644 1
Connecting and logging
If all above is set up correctly, you should now be able to connect to your glftpd as any user, and it should run as your defined gl_user.
Debug logging for the ownerdb transactions will be put in /ftp-data/owner_update.log. Take a peak in it now and then. Reference to this can be found in owner.c.