我有一个守护进程正在运行,这可能会产生一个进程在传入连接。 这是使用execvp()
和fork()
。
问题是,进程不应该以root身份运行,并且进程依赖于正确的用户环境。 所以即时通讯寻求一种方式来加载用户环境。
目前该进程是通过设置gid和uid作为另一个用户执行的。 我已经试过的是使用命令su -l user -c command
,由于某种原因没有工作。
有人有一个想法如何我可以加载用户环境(特别是$HOME
variables)?
提前致谢。
你可以这样做:
#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
注意:请编译两次以生成Debug / Test和Debug / TestProcess
结果:
Running Demon: Home = /root, User ID = 0 Running Process: Home = /home/..., User ID = 1000 ... // The Environment Exit: Home = /root, User ID = 0
sudo有额外的选项-H
,它设置$HOME
变量。 所以你可以试试
sudo -H -u user command
而不是你的su
命令行。