2013-08-26 2 views
2

데몬이 실행 중이며 연결이 끊어지면 프로세스가 생성 될 수 있습니다. 이 작업은 execvp()fork()을 사용하여 수행됩니다.execvp()로 프로세스를 실행할 때 사용자 환경을로드하십시오.

문제는 프로세스가 루트로 실행되어서는 안되며 프로세스가 올바른 사용자 환경에 의존해야한다는 것입니다. 그래서 사용자 환경을로드하는 방법을 찾고 있습니다.

현재 프로세스는 gid와 uid를 설정하여 다른 사용자로 실행됩니다. 내가 이미 시도한 것은 어떤 이유로 작동하지 않는 su -l user -c command 명령으로 사용하고있다.

누군가가 사용자 환경 (특히 $HOME 변수)을로드 할 수있는 아이디어가 있습니까?

미리 감사드립니다.

답변

1

이 같은 그것을 할 수 있습니다

#include <cstring> 
#include <iostream> 
#include <vector> 

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

// Version 0 or 1 
#ifndef VERSION 
#define VERSION 1 
#endif 

// Please compile twise TEST_PROCESS = 0 and TEST_PROCESS = 1 
#ifndef TEST_PROCESS 
#define TEST_PROCESS 0 
#endif 

// User for the process started. 
#ifndef USER 
#error Please define a user (just a name, no string). 
#endif 

#define MAKE_STR(x) DO_MAKE_STR(x) 
#define DO_MAKE_STR(x) #x 
#define USER_NAME MAKE_STR(USER) 

class UserEnvironment 
{ 
    public: 
    typedef std::vector<char*> Values; 

    UserEnvironment(const char* user) { 
     auto cmd = std::string("su - ") + user + " -c '. ~/.profile; env'"; 
     FILE* fp = popen(cmd.c_str(), "r"); 
     if(fp == 0) perror(0); 
     else { 
      char* line = 0; 
      size_t len = 0; 
      ssize_t n = 0; 
      while(1 < (n = getline(&line, &len, fp))) { 
       line[n - 1] = 0; 
       m_values.push_back(line); 
       line = 0; 
      } 
      pclose(fp); 
     } 
     m_values.push_back(0); 
    }; 

    ~UserEnvironment() { 
     m_values.pop_back(); 
     for(char* p: m_values) free(p); 
    } 

    const Values& values() const { return m_values; } 
    Values& values() { return m_values; } 
    operator const Values&() const { return m_values; } 
    operator Values&() { return m_values; } 
    char* const * data() const { return m_values.data(); } 
    char** data() { return m_values.data(); } 

    private: 
    Values m_values; 
}; 

inline const char* get_home() { 
    const char* home = getenv("HOME"); 
    if(home == 0) home = "[Missing]"; 
    return home; 
} 

#if ! TEST_PROCESS 
// Debug/Test 
int main() { 

    const char* user = USER_NAME; 

    int pid = fork(); 
    if(pid < 0) return 1; 
    else if(pid) { 
     const char* home = get_home(); 
     std::cout << "Running Demon: Home = " << home 
      << ", User ID = " << getuid() << std::endl; 
     wait(NULL); 
    } 
    else { 
     struct passwd* pw = getpwnam(user); 
     if(! pw) { 
      std::cout << "Invalid User [" << user << ']'<< std::endl; 
     } 
     else { 
      char* process = strdup("Debug/TestProcess"); 
      char *const argv[] = { 
       process, 
       NULL 
      }; 
     #if VERSION == 0 
      // Oberwrite environment variables. 
      // You might call clearenv(); 
      if(setgid(pw->pw_gid) == 0 && setuid(pw->pw_uid) == 0) { 
       setenv("HOME", pw->pw_dir, 1); 
       execvp(process, argv); 
      } 
     #else 
      // Use the user environt. 
      UserEnvironment environment(user); 
      if(setgid(pw->pw_gid) == 0 && setuid(pw->pw_uid) == 0) { 
       execvpe(process, argv, environment.data()); 
      } 
     #endif 
      free(process); 
     } 
    } 

    const char* home = get_home(); 
    std::cout << "Exit: Home = " << home << ", User ID = " << getuid() << std::endl; 
    return 0; 
} 

#else 

// Debug/TestProcess 
int main() { 
    const char* home = get_home(); 
    std::cout 
     << "Running Process: Home = " << home 
     << ", User ID = " << getuid() 
     << std::endl; 
    system("env"); 
    exit(0); 
} 

#endif 

참고 : 컴파일하십시오를 두 번 디버그/테스트 및 디버그/TestProcess를 생성하는

결과 :

Running Demon: Home = /root, User ID = 0 
Running Process: Home = /home/..., User ID = 1000 
... // The Environment 
Exit: Home = /root, User ID = 0 
0

sudo에는 추가 옵션 -H이 있으며 $HOME 변수를 설정합니다. 그래서 당신은 대신 su 명령 행의

sudo -H -u user command 

을 시도 할 수 있습니다.

+0

내가 sudo는가 설치 해달라고 목표 시스템 (설치되지 않아야 함). 다른 방법이 있습니까? 일반적으로 su -l user -c 명령 접근법이 작동해야합니까, 아니면 여기에 놓친 것이 있습니까? – Markus

관련 문제