#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#include <config.h>
#include <logger.h>

static uid_t
get_uid_for_user(char *user)
{
    if(user == NULL || user[0] == '\0')
    {
        return getuid();
    }
    struct passwd *pwd = calloc(1, sizeof(struct passwd));
    size_t buffer_len = sysconf(_SC_GETPW_R_SIZE_MAX) * sizeof(char);
    char *buffer = malloc(buffer_len);
    getpwnam_r(user, pwd, buffer, buffer_len, &pwd);

    if(pwd == NULL)
    {
        LOGGER_CRIT("couldn't find user to drop privileges\n");
        exit(1);
    }

    uid_t result = pwd->pw_uid;
    free(buffer);
    free(pwd);
    return result;
}

static gid_t
get_gid_for_group(char *group)
{
    if(group == NULL || group[0] == '\0')
    {
        return getgid();
    }
    struct group *grp = calloc(1, sizeof(struct group));
    size_t buffer_len = sysconf(_SC_GETPW_R_SIZE_MAX) * sizeof(char);
    char *buffer = malloc(buffer_len);
    getgrnam_r(group, grp, buffer, buffer_len, &grp);

    if(grp == NULL)
    {
        LOGGER_CRIT("couldn't find group to drop privileges\n");
        exit(1);
    }

    gid_t result = grp->gr_gid;
    free(buffer);
    free(grp);
    return result;
}

int
helper_drop_privileges()
{
    uid_t uid = get_uid_for_user(global_config.user);
    gid_t gid = get_gid_for_group(global_config.group);

    LOGGER_DEBUG("drop privileges to %lu:%lu\n", uid, gid);

    if (setgid(gid) == -1)
    {
        LOGGER_CRIT("failed to drop group privileges\n");
        exit(1);
    }
    if (setuid(uid) == -1)
    {
        LOGGER_CRIT("failed to drop user privileges\n");
        exit(1);
    }

    return 0;
}