2013-08-26 99 views
2

我有一個守護進程正在運行,這可能會產生一個進程在傳入連接。這是通過使用execvp()fork()完成的。使用execvp()執行進程時加載用戶環境;

問題是,進程不應以root身份運行,並且進程依賴於正確的用戶環境。所以即時通訊尋求一種方式來加載用戶環境。

當前通過設置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變量。所以你可以試試

sudo -H -u user command 

而不是你的su命令行。

+0

我沒有安裝須藤目標系統(不應該安裝)。還有別的嗎?通常su -l用戶-c命令方法應該工作,或者我在這裏錯過了一件事情? – Markus