/* Pure Load Balancer - (C)opyleft 2003 Jedi/Sector One <j@pureftpd.org> */

#include <config.h>
#include "plb.h"
#include "plb_globals.h"
#ifdef WITH_DMALLOC
# include <dmalloc.h>
#endif

int plb_drop_caps(const char * const user, const char * const group,
                  const char * const emptydir)
{
    struct passwd *pw;
    struct group *gr;
    gid_t gid;
    uid_t uid;
    int isroot = 0;
    
    if (user == NULL || *user == 0 ||
        group == NULL || *group == 0 || 
        emptydir == NULL || *emptydir == 0) {
        return -1;
    }
    if (geteuid() == (uid_t) 0) {
        isroot = 1;
    }
    if ((pw = getpwnam(user)) != NULL) {
        uid = pw->pw_uid;
    } else {
        uid = (uid_t) strtoul(user, NULL, 10);
    }
    if ((gr = getgrnam(group)) != NULL) {
        gid = gr->gr_gid;
    } else {
        gid = (gid_t) strtoul(group, NULL, 10);
    }
    if (uid <= (uid_t) 0 || gid <= (uid_t) 0) {
        plb_log(LL_FATAL,
                "I will only switch to a non-root/non-wheel uid/gid");
        return -1;
    }
    if (isroot != 0) {
#ifdef HAVE_SETGROUPS
        if (setgroups(1U, &gid) != 0) {
            plb_log(LL_FATAL, "Unable to switch to the requested group");
            return -1;
        }
#endif
        if (chdir(emptydir) != 0 || chroot(emptydir) != 0 ||
            chdir("/") != 0) {
            plb_log(LL_FATAL, "Unable to chroot to [%s] : [%s]", emptydir,
                    strerror(errno));
            return -1;
        }
        if (setgid(gid) || setegid(gid) || setuid(uid) || seteuid(uid) ||
            chdir("/")) {
            plb_log(LL_FATAL, "Unable to switch to [%s]:[%s] : [%s]",
                    user, group, strerror(errno));
            return -1;
        }
    } else {
        if (geteuid() != uid) {
            plb_log(LL_WARNING, "Uid [%lu] requested in configuration file, "
                    "but your effective uid is [%lu]", 
                    (unsigned long) uid, (unsigned long) geteuid());
        }
        if (chdir(emptydir) != 0) {
            plb_log(LL_WARNING, "[%s] is not reachable : [%s]",
                    emptydir, strerror(errno));
        }
    }
    if (isroot != 0) {
        plb_log(LL_NOTIFY, "Switching to [%s]:[%s], chrooting to [%s]",
                user, group, emptydir);
    } else {
        plb_log(LL_NOTIFY, "Software started by a non-root user");
    }
    
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1