/* slimski - Simple Login Manager
   Copyright (C) 1997, 1998 Per Liden
   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>
   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
*/

#include <cstdio>

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "switchuser.h"
#include "util.h"
#include "log.h"

using namespace std;

SwitchUser::SwitchUser(struct passwd *pw, Cfg *c, const string& display, char** _env)
    : cfg(c),  Pw(pw),  displayName(display),  env(_env) {
}

SwitchUser::~SwitchUser() { }

void SwitchUser::Login(const char* cmd, const char* mcookie) {
    SetUserId();
    SetClientAuth(mcookie);
    ExecuteLC(cmd);
}

void SwitchUser::SetUserId() {
    if( (Pw == 0)  ||  (initgroups(Pw->pw_name, Pw->pw_gid) != 0) ||
        (setgid(Pw->pw_gid) != 0)  ||  (setuid(Pw->pw_uid) != 0)    )
    {
            logStream << "slimski: could not switch to the specified user id" << endl;
            exit(ERR_EXIT);
    }
}

/**        howdy bub           after bugtesting, consider reinstating this modified fn
void SwitchUser::ExecuteLC(const char* cmd) {
    if (chdir(Pw->pw_dir) == 0) {              //  the target user account may not have a home directory, eh
        execle(Pw->pw_shell, Pw->pw_shell, "-c", cmd, NULL, env);
        logStream << "[slimski:SwitchUser] could not execute the specified login command" << endl;
    } else {
        logStream << "[slimski:SwitchUser] chdir() to Pw->pw_dir failed" << endl;   // switchuser is unaware of zeebug
    }
}
*/
void SwitchUser::ExecuteLC(const char* cmd) {
    chdir(Pw->pw_dir);
    execle(Pw->pw_shell, Pw->pw_shell, "-c", cmd, NULL, env);
    logStream <<  "slimski: could not execute the specified login command" << endl;
}




/**      howdy bub      after bugtesting, consider reinstating this modified fn
void SwitchUser::SetClientAuth(const char* mcookie) {
    string home = string(Pw->pw_dir);
    string authfile = home + "/.Xauthority";
    struct stat statbuf;
    if ( stat(authfile.c_str(), &statbuf) == 0 ) {
        // ^--- returns -1 if the file does not exist or has been locked by another program or if the file is otherwise inaccessible to caller
        int fussy = remove(authfile.c_str());
        if (fussy != 0) {
            logStream << "[slimski:SwitchUser] unable to remove preexisting ~/.Xauthority file" << endl;
        }
    }
    Util::add_mcookie(mcookie, ":0", cfg->getOption("xauth_path"), authfile);
}
*/
void SwitchUser::SetClientAuth(const char* mcookie) {
    bool r;     // howdy    why assigned
    string home = string(Pw->pw_dir);
    string authfile = home + "/.Xauthority";
    remove(authfile.c_str());
    r = Util::add_mcookie(mcookie, ":0", cfg->getOption("xauth_path"), authfile);
}
