コード例 #1
0
void redemption_new_session(CryptoContext & cctx, char const * config_filename)
{
    char text[256];
    char source_ip[256];
    int target_port = 0;
    char real_target_ip[256];

    union
    {
        struct sockaddr s;
        struct sockaddr_storage ss;
        struct sockaddr_in s4;
        struct sockaddr_in6 s6;
    } u;
    int sock_len = sizeof(u);

    Inifile ini;
    { ConfigurationLoader cfg_loader(ini.configuration_holder(), config_filename); }

    init_signals();
    snprintf(text, 255, "redemption_%8.8x_main_term", unsigned(getpid()));

    getpeername(0, &u.s, reinterpret_cast<socklen_t *>(&sock_len));
    strcpy(source_ip, inet_ntoa(u.s4.sin_addr));

    union
    {
        struct sockaddr s;
        struct sockaddr_storage ss;
        struct sockaddr_in s4;
        struct sockaddr_in6 s6;
    } localAddress;
    socklen_t addressLength = sizeof(localAddress);

    int sck = 0;
    if (-1 == getsockname(sck, &localAddress.s, &addressLength)){
        LOG(LOG_INFO, "getsockname failed error=%s", strerror(errno));
        _exit(1);
    }

    target_port = localAddress.s4.sin_port;
    strcpy(real_target_ip, inet_ntoa(localAddress.s4.sin_addr));

    if (ini.get<cfg::globals::enable_ip_transparent>()) {
        const int source_port = 0;
        char target_ip[256];
        strcpy(target_ip, inet_ntoa(localAddress.s4.sin_addr));
        int fd = open("/proc/net/ip_conntrack", O_RDONLY);
        // source and dest are inverted because we get the information we want from reply path rule
        int res = parse_ip_conntrack(fd, target_ip, source_ip, target_port, source_port, real_target_ip, sizeof(real_target_ip));
        if (res){
            LOG(LOG_WARNING, "Failed to get transparent proxy target from ip_conntrack");
        }
        close(fd);
    }


    ini.set_acl<cfg::globals::host>(source_ip);
    ini.set_acl<cfg::globals::target>(real_target_ip);

    if (ini.get<cfg::debug::session>()){
        LOG(LOG_INFO, "Setting new session socket to %d\n", sck);
    }

    int nodelay = 1;
    if (0 == setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&nodelay), sizeof(nodelay))){
        Session session(sck, ini, cctx);

        if (ini.get<cfg::debug::session>()){
            LOG(LOG_INFO, "Session::end of Session(%u)", sck);
        }

        shutdown(sck, 2);
        close(sck);
    }
    else {
        LOG(LOG_INFO, "Failed to set socket TCP_NODELAY option on client socket");
    }

}
コード例 #2
0
ファイル: session_server.hpp プロジェクト: tvi123/redemption
    virtual Server_status start(int incoming_sck)
    {
        union
        {
            struct sockaddr s;
            struct sockaddr_storage ss;
            struct sockaddr_in s4;
            struct sockaddr_in6 s6;
        } u;
        unsigned int sin_size = sizeof(u);
        memset(&u, 0, sin_size);

        int sck = accept(incoming_sck, &u.s, &sin_size);
        if (-1 == sck) {
            LOG(LOG_INFO, "Accept failed on socket %u (%s)", incoming_sck, strerror(errno));
            _exit(1);
        }

        char source_ip[256];
        strcpy(source_ip, inet_ntoa(u.s4.sin_addr));
        const int source_port = ntohs(u.s4.sin_port);
        /* start new process */
        const pid_t pid = fork();
        switch (pid) {
        case 0: /* child */
            {
                close(incoming_sck);

                Inifile ini;
                ini.set<cfg::debug::config>(this->debug_config);
                { ConfigurationLoader cfg_loader(ini, this->config_filename.c_str()); }

                if (ini.get<cfg::globals::wab_agent_alternate_shell>().empty()) {
                    ini.set<cfg::globals::wab_agent_alternate_shell>(
                        this->parametersHldr.get_agent_alternate_shell()
                    );
                }

                ini.get_ref<cfg::crypto::key0>().setmem(this->parametersHldr.get_crypto_key_0());
                ini.get_ref<cfg::crypto::key1>().setmem(this->parametersHldr.get_crypto_key_1());

                if (ini.get<cfg::debug::session>()){
                    LOG(LOG_INFO, "Setting new session socket to %d\n", sck);
                }

                union
                {
                    struct sockaddr s;
                    struct sockaddr_storage ss;
                    struct sockaddr_in s4;
                    struct sockaddr_in6 s6;
                } localAddress;
                socklen_t addressLength = sizeof(localAddress);


                if (-1 == getsockname(sck, &localAddress.s, &addressLength)){
                    LOG(LOG_INFO, "getsockname failed error=%s", strerror(errno));
                    _exit(1);
                }

                char target_ip[256];
                const int target_port = ntohs(localAddress.s4.sin_port);
//                strcpy(real_target_ip, inet_ntoa(localAddress.s4.sin_addr));
                strcpy(target_ip, inet_ntoa(localAddress.s4.sin_addr));

                if (0 != strcmp(source_ip, "127.0.0.1")){
                    // do not log early messages for localhost (to avoid tracing in watchdog)
                    LOG(LOG_INFO, "src=%s sport=%d dst=%s dport=%d", source_ip, source_port, target_ip, target_port);
                }

                char real_target_ip[256];
                if (ini.get<cfg::globals::enable_ip_transparent>() &&
                    (0 != strcmp(source_ip, "127.0.0.1"))) {
                    int fd = open("/proc/net/ip_conntrack", O_RDONLY);
                    // source and dest are inverted because we get the information we want from reply path rule
                    int res = parse_ip_conntrack(fd, target_ip, source_ip, target_port, source_port, real_target_ip, sizeof(real_target_ip), 1);
                    if (res){
                        LOG(LOG_WARNING, "Failed to get transparent proxy target from ip_conntrack: %d", fd);
                    }
                    close(fd);

                    if (setgid(this->gid) != 0){
                        LOG(LOG_WARNING, "Changing process group to %u failed with error: %s\n", this->gid, strerror(errno));
                        _exit(1);
                    }
                    if (setuid(this->uid) != 0){
                        LOG(LOG_WARNING, "Changing process group to %u failed with error: %s\n", this->gid, strerror(errno));
                        _exit(1);
                    }

                    LOG(LOG_INFO, "src=%s sport=%d dst=%s dport=%d", source_ip, source_port, real_target_ip, target_port);
                }
                else {
                    ::memset(real_target_ip, 0, sizeof(real_target_ip));
                }

                int nodelay = 1;
                if (0 == setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay))){
                    // Create session file
                    int child_pid = getpid();
                    char session_file[256];
                    sprintf(session_file, "%s/redemption/session_%d.pid", PID_PATH, child_pid);
                    int fd = open(session_file, O_WRONLY | O_CREAT, S_IRWXU);
                    if (fd == -1) {
                        LOG(LOG_ERR, "Writing process id to SESSION ID FILE failed. Maybe no rights ?:%d:%d\n", errno, strerror(errno));
                        _exit(1);
                    }
                    char text[256];
                    const size_t lg = snprintf(text, 255, "%d", child_pid);
                    if (write(fd, text, lg) == -1) {
                        LOG(LOG_ERR, "Couldn't write pid to %s: %s", PID_PATH "/redemption/session_<pid>.pid", strerror(errno));
                        _exit(1);
                    }
                    close(fd);

                    // Launch session
                    if (0 != strcmp(source_ip, "127.0.0.1")){
                        // do not log early messages for localhost (to avoid tracing in watchdog)
                        LOG(LOG_INFO,
                            "New session on %u (pid=%u) from %s to %s",
                            (unsigned)sck, (unsigned)child_pid, source_ip, (real_target_ip[0] ? real_target_ip : target_ip));
                    }
                    ini.set_acl<cfg::globals::host>(source_ip);
//                    ini.context_set_value(AUTHID_TARGET, real_target_ip);
                    ini.set_acl<cfg::globals::target>(target_ip);
                    if (ini.get<cfg::globals::enable_ip_transparent>()
                        &&  strncmp(target_ip, real_target_ip, strlen(real_target_ip))) {
                        ini.set_acl<cfg::context::real_target_device>(real_target_ip);
                    }
                    Session session(sck, ini);

                    // Suppress session file
                    unlink(session_file);

                    if (ini.get<cfg::debug::session>()){
                        LOG(LOG_INFO, "Session::end of Session(%u)", sck);
                    }

                    shutdown(sck, 2);
                    close(sck);
                }
                else {
                    LOG(LOG_ERR, "Failed to set socket TCP_NODELAY option on client socket");
                }
                return START_WANT_STOP;
            }
            break;
        default: /* father */
            {
                close(sck);
            }
            break;
        case -1:
            // error forking
            LOG(LOG_ERR, "Error creating process for new session : %s\n", strerror(errno));
            break;
        }
        return START_FAILED;
    }
コード例 #3
0
ファイル: transparent.cpp プロジェクト: nrich/redemption
int main(int argc, char * argv[]) {
    openlog("transparent", LOG_CONS | LOG_PERROR, LOG_USER);

    const char * copyright_notice =
        "\n"
        "ReDemPtion Transparent Proxy " VERSION ".\n"
        "Copyright (C) Wallix 2010-2015.\n"
        "Christophe Grosjean, Raphael Zhou.\n"
        "\n"
        ;

    std::string input_filename;
    std::string output_filename;
    std::string target_device;
    uint32_t    target_port;
    std::string username;
    std::string password;
    std::string record_filename;
    std::string play_filename;
    std::string persistent_key_list_filename;

    persistent_key_list_filename = "./PersistentKeyList.bin";
    target_port                  = 3389;

    program_options::options_description desc({
        {'h', "help",    "produce help message"},
        {'v', "version", "show software version"},

        {'i', "input-file",    &input_filename,               "input ini file name"},
        {'o', "output-file",   &output_filename,              "output int file name"},
        {'t', "target-device", &target_device,                "target device[:port]"},
        {'u', "username",      &username,                     "username"},
        {'p', "password",      &password,                     "password"},
        {'k', "key-list-file", &persistent_key_list_filename, "persistent key list file name"},

        {'r', "record-file",   &record_filename,              "record file name"},
        {'d', "play-file",     &play_filename,                "play file name"},
    });

    auto options = program_options::parse_command_line(argc, argv, desc);

    if (options.count("help") > 0) {
        std::cout << copyright_notice;
        std::cout << "Usage: rdptproxy [options]\n\n";
        std::cout << desc << endl;
        exit(0);
    }

    if (options.count("version") > 0) {
        std::cout << copyright_notice;
        exit(0);
    }

    if (   target_device.empty()
        && play_filename.empty()) {
        std::cerr << "Missing target device or play file name: use -t target or -d filename\n\n";
        exit(-1);
    }

    if (   !target_device.empty()
        && !play_filename.empty()) {
        std::cerr << "Use -t target or -d filename\n\n";
        exit(-1);
    }

    if (   !output_filename.empty()
        && !play_filename.empty()) {
        std::cerr << "Use -o filename or -d filename\n\n";
        exit(-1);
    }

    if (   !record_filename.empty()
        && !play_filename.empty()) {
        std::cerr << "Use -r filename or -d filename\n\n";
        exit(-1);
    }

    if (   !input_filename.empty()
        && !output_filename.empty()) {
        std::cerr << "Use -i filename or -o filename\n\n";
        exit(-1);
    }

    if (!target_device.empty()) {
        size_t pos = target_device.find(':');
        if (pos != string::npos) {
            target_port = atoi(target_device.substr(pos + 1).c_str());
            target_device.resize(pos);
        }

        if (username.c_str()[0] == 0) {
            std::cerr << "Missing username : use -u username\n\n";
            exit(-1);
        }
    }

    if (password.empty()) {
        password = "";
    }


    // This server only support one incoming connection before closing listener
    class ServerOnce : public Server {
    public:
        int  sck;
        char ip_source[256];

        ServerOnce() : sck(0) {
           this->ip_source[0] = 0;
        }

        virtual Server_status start(int incoming_sck) {
            union {
                struct sockaddr s;
                struct sockaddr_storage ss;
                struct sockaddr_in s4;
                struct sockaddr_in6 s6;
            } u;
            unsigned int sin_size = sizeof(u);
            memset(&u, 0, sin_size);
            this->sck = accept(incoming_sck, &u.s, &sin_size);
            strcpy(this->ip_source, inet_ntoa(u.s4.sin_addr));
            LOG(LOG_INFO, "Incoming socket to %d (ip=%s)\n", this->sck, this->ip_source);
            return START_WANT_STOP;
        }
    } one_shot_server;
    Listen listener(one_shot_server, 0, 3389, true, 5);  // 25 seconds to connect, or timeout
    listener.run();

    Inifile             ini;
    ConfigurationLoader cfg_loader(ini, CFG_PATH "/" RDPPROXY_INI);

    int nodelay = 1;
    if (-1 == setsockopt( one_shot_server.sck, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay
                        , sizeof(nodelay))) {
        LOG(LOG_ERR, "Failed to set socket TCP_NODELAY option on client socket");
    }
    SocketTransport front_trans( "RDP Client", one_shot_server.sck, "0.0.0.0", 0
                               , ini.debug.front, 0);
    wait_obj front_event;

    LCGRandom gen(0);

    // Remove existing Persistent Key List file.
    unlink(persistent_key_list_filename.c_str());

    OutFileTransport * persistent_key_list_oft = NULL;
    int                persistent_key_list_ofd;

    persistent_key_list_ofd = open(persistent_key_list_filename.c_str(),
                                   O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
    if (persistent_key_list_ofd != -1) {
        persistent_key_list_oft = new OutFileTransport(persistent_key_list_ofd);
    }
    else {
        LOG(LOG_ERR, "Failed to open Persistent Key List file to writing: name=\"%s\"",
            persistent_key_list_filename.c_str());
    }

    const bool fastpath_support = true;
    const bool mem3blt_support  = true;
    Front front(front_trans, SHARE_PATH "/" DEFAULT_FONT_NAME, gen, ini,
        fastpath_support, mem3blt_support, input_filename.c_str(), persistent_key_list_oft);
    null_mod no_mod(front);

    while (front.up_and_running == 0) {
        front.incoming(no_mod);
    }

    LOG(LOG_INFO, "hostname=\"%s\"", front.client_info.hostname);


    try {
        if (target_device.empty()) {
            TransparentReplayMod mod(front, play_filename.c_str(),
                front.client_info.width, front.client_info.height, NULL, ini.font);

            run_mod(mod, front, front_event, nullptr, &front_trans);
        }
        else {
            OutFileTransport * record_oft = NULL;
            int                record_fd  = -1;

            if (!record_filename.empty()) {
                record_fd = open(record_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
                                   S_IRUSR | S_IWUSR | S_IRGRP);
                if (record_fd != -1) {
                    record_oft = new OutFileTransport(record_fd);
                }
                else {
                    LOG(LOG_ERR, "Failed to open record file to writing: name=\"%s\"",
                        record_filename.c_str());
                }
            }

            InFileTransport * persistent_key_list_ift = NULL;
            int               persistent_key_list_ifd;

            persistent_key_list_ifd = open(persistent_key_list_filename.c_str(), O_RDONLY);
            if (persistent_key_list_ifd != -1) {
                persistent_key_list_ift = new InFileTransport(persistent_key_list_ifd);
            }
            else {
                LOG(LOG_ERR, "Failed to open Persistent Key List file to reading: name=\"%s\"",
                    persistent_key_list_filename.c_str());
            }

            int client_sck = ip_connect(target_device.c_str(), target_port, 3, 1000, ini.debug.mod_rdp);
            SocketTransport mod_trans( "RDP Server", client_sck, target_device.c_str(), target_port
                                     , ini.debug.mod_rdp, &ini.context.auth_error_message);

            ClientInfo client_info = front.client_info;

            ModRDPParams mod_rdp_params( username.c_str()
                                       , password.c_str()
                                       , target_device.c_str()
                                       , "0.0.0.0"   // client ip is silenced
                                       , front.keymap.key_flags
                                       , ini.debug.mod_rdp
                                       );
            //mod_rdp_params.enable_tls                          = true;
            mod_rdp_params.enable_nla                          = ini.mod_rdp.enable_nla;
            mod_rdp_params.enable_krb                          = ini.mod_rdp.enable_kerberos;
            //mod_rdp_params.enable_fastpath                     = true;
            //mod_rdp_params.enable_mem3blt                      = true;
            mod_rdp_params.enable_bitmap_update                = ini.globals.enable_bitmap_update;
            //mod_rdp_params.enable_new_pointer                  = true;
            mod_rdp_params.enable_transparent_mode             = true;
            mod_rdp_params.output_filename                     = (output_filename.empty() ? "" : output_filename.c_str());
            mod_rdp_params.persistent_key_list_transport       = persistent_key_list_ift;
            mod_rdp_params.transparent_recorder_transport      = record_oft;
            mod_rdp_params.auth_channel                        = ini.globals.auth_channel;
            mod_rdp_params.alternate_shell                     = ini.globals.alternate_shell.get_cstr();
            mod_rdp_params.shell_working_directory             = ini.globals.shell_working_directory.get_cstr();
            mod_rdp_params.rdp_compression                     = ini.mod_rdp.rdp_compression;
            mod_rdp_params.disconnect_on_logon_user_change     = ini.mod_rdp.disconnect_on_logon_user_change;
            mod_rdp_params.open_session_timeout                = ini.mod_rdp.open_session_timeout;
            mod_rdp_params.certificate_change_action           = ini.mod_rdp.certificate_change_action;
            mod_rdp_params.extra_orders                        = ini.mod_rdp.extra_orders.c_str();
            mod_rdp_params.enable_persistent_disk_bitmap_cache = ini.mod_rdp.persistent_disk_bitmap_cache;
            mod_rdp_params.enable_cache_waiting_list           = ini.mod_rdp.cache_waiting_list;
            mod_rdp_params.password_printing_mode              = ini.debug.password;
            mod_rdp_params.cache_verbose                       = ini.debug.cache;

            mod_rdp_params.allow_channels                      = &(ini.mod_rdp.allow_channels);
            mod_rdp_params.deny_channels                       = &(ini.mod_rdp.deny_channels);

            mod_rdp mod(mod_trans, front, client_info, ini.mod_rdp.redir_info,
                        gen, mod_rdp_params);

            run_mod(mod, front, front_event, &mod_trans, &front_trans);

            if (client_sck != -1) {
                shutdown(client_sck, 2);
                close(client_sck);
            }

            if (persistent_key_list_ifd != -1) {
                delete persistent_key_list_ift;

                close(persistent_key_list_ifd);
            }

            if (record_fd != -1) {
                delete record_oft;

                close(record_fd);
            }
        }
    }   // try
    catch (Error & e) {
        LOG(LOG_ERR, "errid = %d", e.id);
    }

    front.disconnect();

    if (persistent_key_list_ofd != -1) {
        delete persistent_key_list_oft;

        close(persistent_key_list_ofd);
    }

    shutdown(one_shot_server.sck, 2);
    close(one_shot_server.sck);

    LOG(LOG_INFO, "Listener closed\n");
    LOG(LOG_INFO, "Incoming socket %d (ip=%s)\n", one_shot_server.sck, one_shot_server.ip_source);

    return 0;
}
コード例 #4
0
ファイル: mainloop.cpp プロジェクト: cuzz/redemption
void redemption_new_session()
{
    char text[256];
    char source_ip[256];
    int source_port = 0;
    char target_ip[256];
    int target_port = 0;
    char real_target_ip[256];

    union
    {
        struct sockaddr s;
        struct sockaddr_storage ss;
        struct sockaddr_in s4;
        struct sockaddr_in6 s6;
    } u;
    int sock_len = sizeof(u);

    Inifile ini;
    ConfigurationLoader cfg_loader(ini, CFG_PATH "/" RDPPROXY_INI);

    init_signals();
    snprintf(text, 255, "redemption_%8.8x_main_term", getpid());

    getpeername(0, &u.s, (socklen_t *)&sock_len);
    strcpy(source_ip, inet_ntoa(u.s4.sin_addr));

    union
    {
        struct sockaddr s;
        struct sockaddr_storage ss;
        struct sockaddr_in s4;
        struct sockaddr_in6 s6;
    } localAddress;
    socklen_t addressLength = sizeof(localAddress);

    int sck = 0;
    if (-1 == getsockname(sck, &localAddress.s, &addressLength)){
        LOG(LOG_INFO, "getsockname failed error=%s", strerror(errno));
        _exit(1);
    }

    target_port = localAddress.s4.sin_port;
    strcpy(real_target_ip, inet_ntoa(localAddress.s4.sin_addr));

    if (ini.globals.enable_ip_transparent) {
        strcpy(target_ip, inet_ntoa(localAddress.s4.sin_addr));
        int fd = open("/proc/net/ip_conntrack", O_RDONLY);
        // source and dest are inverted because we get the information we want from reply path rule
        int res = parse_ip_conntrack(fd, target_ip, source_ip, target_port, source_port, real_target_ip, sizeof(real_target_ip));
        if (res){
            LOG(LOG_WARNING, "Failed to get transparent proxy target from ip_conntrack");
        }
        close(fd);
    }


    ini.context_set_value(AUTHID_HOST, source_ip);
    ini.context_set_value(AUTHID_TARGET, real_target_ip);

    if (ini.debug.session){
        LOG(LOG_INFO, "Setting new session socket to %d\n", sck);
    }

    int nodelay = 1;
    if (0 == setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay))){
        wait_obj front_event(sck);

        Session session(front_event, sck, &ini);

        if (ini.debug.session){
            LOG(LOG_INFO, "Session::end of Session(%u)", sck);
        }

        shutdown(sck, 2);
        close(sck);
    }
    else {
        LOG(LOG_INFO, "Failed to set socket TCP_NODELAY option on client socket");
    }

}
コード例 #5
0
int app_proxy(
    int argc, char const * const * argv, const char * copyright_notice
  , CryptoContext & cctx
  , ExtraOptions const & extrax_options, ExtracOptionChecker extrac_options_checker
  , PreLoopFn pre_loop_fn = PreLoopFn()
) {
    setlocale(LC_CTYPE, "C");

    const unsigned uid = getuid();
    const unsigned gid = getgid();

    unsigned euid = uid;
    unsigned egid = gid;

    std::string config_filename = CFG_PATH "/" RDPPROXY_INI;

    program_options::options_description desc({
        {'h', "help", "produce help message"},
        {'v', "version", "show software version"},
        {'k', "kill", "shut down rdpproxy"},
        {'n', "nodaemon", "don't fork into background"},

        {'u', "uid", &euid, "run with given uid"},

        {'g', "gid", &egid, "run with given gid"},

        //{'t', "trace", "trace behaviour"},

        {'c', "check", "check installation files"},

        {'f', "force", "remove application lock file"},

        {'i', "inetd", "launch redemption with inetd like launcher"},

        {"config-file", &config_filename, "used an another ini file"},

        //{"test", "check Inifile syntax"}
    });

    for (extra_option const & extra : extrax_options) {
        desc.add({extra.option_long, extra.description});
    }

    auto options = program_options::parse_command_line(argc, const_cast<char**>(argv), desc);

    if (options.count("kill")) {
        int status = shutdown(PID_PATH "/redemption/" LOCKFILE);
        if (status){
            // TODO check the real error that occured
            std::clog << "problem opening " << PID_PATH "/redemption/" LOCKFILE  << "."
            " Maybe rdpproxy is not running\n";
        }
        return status;
    }
    if (options.count("help")) {
        std::cout << copyright_notice << "\n\n";
        std::cout << "Usage: rdpproxy [options]\n\n";
        std::cout << desc << std::endl;
        return 0;
    }
    if (options.count("version")) {
        std::cout << copyright_notice << std::endl;
        return 0;
    }

    {
        bool quit = false;
        if (int status = extrac_options_checker(options, &quit)) {
            return status;
        }
        else if (quit) {
            return 0;
        }
    }

    openlog("rdpproxy", LOG_CONS | LOG_PERROR, LOG_USER);

    if (options.count("check")) {
        bool user_check_file_result  =
            ((uid != euid) || (gid != egid)) ?
            CheckFile::check(user_check_file_list) : true;
        /*
          setgid(egid);
          setuid(euid);
        */
        bool euser_check_file_result = CheckFile::check(euser_check_file_list);
        /*
          setgid(gid);
          setuid(uid);
        */

        if ((uid != euid) || (gid != egid)) {
            CheckFile::ShowAll(user_check_file_list, uid, gid);
        }
        CheckFile::ShowAll(euser_check_file_list, euid, egid);

        if (!user_check_file_result || !euser_check_file_result)
        {
            if ((uid != euid) || (gid != egid))
            {
                CheckFile::ShowErrors(user_check_file_list, uid, gid);
            }
            CheckFile::ShowErrors(euser_check_file_list, euid, egid);

            LOG(LOG_INFO, "%s",
                "Please verify that all tests passed. If not, "
                    "you may need to remove " PID_PATH "/redemption/"
                    LOCKFILE " or reinstall rdpproxy if some configuration "
                    "files are missing.");
        }
        return 0;
    }

    if (options.count("inetd")) {
        redemption_new_session(cctx, config_filename.c_str());
        return 0;
    }

    // if -f (force option) is set
    // force kill running rdpproxy
    // force remove pid file
    // don't check if it fails (proxy may be allready stopped)
    // and try to continue normal start process afterward

    if (mkdir(PID_PATH "/redemption", 0700) < 0){
        // TODO check only for relevant errors (exists with expected permissions is OK)
    }

    if (chown(PID_PATH "/redemption", euid, egid) < 0){
        LOG(LOG_INFO, "Failed to set owner %u.%u to " PID_PATH "/redemption", euid, egid);
        return 1;
    }

    if (options.count("force")){
        shutdown(PID_PATH  "/redemption/" LOCKFILE);
    }

    if (0 == access(PID_PATH "/redemption/" LOCKFILE, F_OK)) {
        std::clog <<
        "File " << PID_PATH "/redemption/" LOCKFILE << " already exists. "
        "It looks like rdpproxy is already running, "
        "if not, try again with -f (force) option or delete the " PID_PATH "/redemption/" LOCKFILE " file and try again\n";
        return 1;
    }


    /* write the pid to file */
    int fd = open(PID_PATH "/redemption/" LOCKFILE, O_WRONLY | O_CREAT, S_IRWXU);
    if (fd == -1) {
        std::clog
        <<  "Writing process id to " PID_PATH "/redemption/" LOCKFILE " failed. Maybe no rights ?"
        << " : " << errno << ":'" << strerror(errno) << "'\n";
        return 1;
    }
    {
        io::posix::fdbuf file(fd);
        const int pid = getpid();
        char text[256];
        size_t lg = snprintf(text, 255, "%d", pid);
        if (file.write(text, lg) == -1) {
            LOG(LOG_ERR, "Couldn't write pid to %s: %s", PID_PATH "/redemption/" LOCKFILE, strerror(errno));
            return 1;
        }
    }

    if (!options.count("nodaemon")) {
        daemonize(PID_PATH "/redemption/" LOCKFILE);
    }

    Inifile ini;
    { ConfigurationLoader cfg_loader(ini.configuration_holder(), config_filename.c_str()); }

    OpenSSL_add_all_digests();

    if (!ini.get<cfg::globals::enable_ip_transparent>()) {
        if (setgid(egid) != 0){
            LOG(LOG_ERR, "Changing process group to %u failed with error: %s\n", egid, strerror(errno));
            return 1;
        }
        if (setuid(euid) != 0){
            LOG(LOG_ERR, "Changing process user to %u failed with error: %s\n", euid, strerror(errno));
            return 1;
        }
    }

    pre_loop_fn(ini);

    LOG(LOG_INFO, "ReDemPtion " VERSION " starting");
    redemption_main_loop(ini, cctx, euid, egid, std::move(config_filename));

    /* delete the .pid file if it exists */
    /* don't care about errors. */
    /* If we are not in daemon mode this file will not exists, */
    /* hence some errors are expected */
    unlink(PID_PATH "/redemption/" LOCKFILE);

    return 0;
}