in uima-ducc-spawn/src/ducc_ling.c [618:872]
int main(int argc, char **argv, char **envp)
{
int i;
int opt;
char *userid = NULL;
char *filepath = NULL;
char *workingdir = NULL;
char *logfile = NULL;
struct passwd *pwd= NULL;
int switch_ids = 0;
int redirect = 0;
char buf[BUFLEN];
int append = 0;
// don't allow root to exec a process
if ( getuid() == 0 ) {
log_stderr("400 Can't run ducc_ling as root\n");
exit(1);
}
while ( (opt = getopt(argc, argv, "af:w:u:vqh?") ) != -1) {
switch (opt) {
case 'a':
append = 1;
break;
case 'u':
userid = optarg;
break;
case 'f':
filepath = optarg;
break;
case 'w':
workingdir = optarg;
break;
case 'v':
version();
exit(0);
break;
case 'q':
quiet = 1;
break;
case 'h':
case '?':
usage();
default:
log_stderr("100 Unrecognized argument %s\n", optarg);
usage();
}
}
argc -= optind;
argv += optind;
version(); // this gets echoed into the Agent's log
if ( userid == NULL ) {
log_stderr("200 missing userid\n");
exit(1);
}
if ( getenv("DUCC_CONSOLE_LISTENER") != NULL ) {
log_stdout("302 Redirecting console into socket %s.\n", getenv("DUCC_CONSOLE_LISTENER"));
redirect = 1;
} else if ( filepath != NULL ) {
log_stdout("301 Redirecting console into file %s.\n", filepath);
redirect = 1;
}
// do this here before redirection stdout / stderr
log_stdout("0 %d\n", getpid()); // code 0 means we passed tests and are about to dup I/O
// fetch installed "ducc" user passwd structure
pwd = getpwnam(UID);
if ( pwd == NULL ) {
pwd = getpwuid(getuid());
#ifdef __APPLE__
// Seems theres a bug in getpwuid and nobody seems to have a good answer. On mac we don't
// care anyway so we ignore it (because mac is supported for test only).
if ( pwd == NULL ) {
log_stdout("600 No \"%s\" user found and I can't find my own name. Running as id %d", UID, getuid());
} else {
log_stdout("600 No \"%s\" user found, running instead as %s.\n", UID, pwd->pw_name);
}
#else
log_stdout("600 No \"%s\" user found, running instead as %s.\n", UID, pwd->pw_name);
#endif
} else if ( pwd->pw_uid != getuid() ) {
log_stdout("700 Caller is not %s (%d), not trying to switch ids ... \n", UID, pwd->pw_uid);
pwd = getpwuid(getuid());
log_stdout("800 Running instead as %s.\n", pwd->pw_name);
} else {
// Invoked by the owning "ducc" id so check if can switch, i.e. running as root
if (geteuid() == 0) {
switch_ids = 1;
}
}
//
// Fetch target user's passwd structure and switch identities.
// Don't allow a switch to a fake or "system" id.
// If not switching then the target uid may be real or fake.
// Fake ids are used when running on a simulated cluster.
//
if ( switch_ids ) {
pwd = getpwnam(userid);
if ( pwd == NULL ) {
log_stderr("820 User \"%s\" does not exist.\n", userid);
exit(1);
}
// don't allow a change to a "system" uid
if ( pwd->pw_uid < MIN_UID ) {
log_stderr("900 setuid < %d not allowed. Exiting.\n", MIN_UID);
exit(1);
}
if ( initgroups(userid, pwd->pw_gid) != 0 ) {
snprintf(buf, STRLEN, "1100 Unable to initialize groups for %s.", userid);
buf[STRLEN] = '\0';
perror(buf);
} else {
log_stdout("830 User groups are initialized for %s.\n", userid);
}
if ( setgid(pwd->pw_gid) != 0 ) {
snprintf(buf, STRLEN, "1101 Unable to switch group for %s.",userid);
buf[STRLEN] = '\0';
perror(buf);
} else {
log_stdout("840 Switched to group %d.\n", pwd-> pw_gid);
}
if ( setuid(pwd->pw_uid) != 0 ) {
snprintf(buf, STRLEN, "1102 Unable to switch to user id %s.",userid);
buf[STRLEN] = '\0';
perror(buf);
} else {
log_stdout("850 Switched to user %d.\n", pwd-> pw_uid);
}
}
uid_t my_effective_id = geteuid();
if ( my_effective_id == 0 ) {
log_stdout("851 ID switch fails. Check ducc_ling ownership and privileges.\n");
exit(1);
}
show_ids(userid);
set_umask(); // Set umask befor creating logfiles
if ( redirect && ( filepath != NULL) ) {
logfile = mklogfile(filepath);
} else {
log_stdout("300 Bypassing redirect of log.\n");
}
if ( append ) {
return do_append(filepath, argc, argv);
}
set_limits(); // AFTER the switch, set soft and limits if needed
query_limits(); // Once, for the agent
renice();
//
// Set up logging dir. We have switched by this time so we can't do anything the user couldn't do.
//
if ( redirect ) {
char *console_port = getenv("DUCC_CONSOLE_LISTENER");
if ( console_port == NULL ) {
redirect_to_file(filepath);
} else if ( !strncmp(console_port, "suppress", strlen("suppress") ) ) {
log_stdout("303 Redirect stdout and stderr to /dev/null.\n");
redirect_to_file("/dev/null");
} else {
fflush(stdout);
redirect_to_socket(console_port);
if ( filepath != NULL ) {
// on console redirection, spit out the name of the log file it would have been
log_stdout("1002 CONSOLE_REDIRECT %s\n", logfile);
}
}
// Start with the current date-time
time_t now = time(0);
log_stdout(ctime(&now));
version(); // this gets echoed as first message into the redirected log
query_limits(); // Once, for the user
}
//
// chdir to working dir if specified
//
if ( workingdir != NULL ) {
int rc = chdir(workingdir);
if ( rc == -1 ) {
snprintf(buf, STRLEN, "1110 Unable to switch to working directory %s.", workingdir);
buf[STRLEN] = '\0';
perror(buf);
exit(1);
}
log_stdout("1120 Changed to working directory %s\n", workingdir);
}
//
// Translate DUCC_LD_LIBRARY_PATH into LD_LIBRARY_PATH, if it exists.
//
int env_index = -1;
char ** pathstr = NULL;
while ( envp[++env_index] != NULL ) {
char *srchstring = "DUCC_LD_LIBRARY_PATH=";
int len = strlen(srchstring);
if ( strncmp(envp[env_index], srchstring, len) == 0 ) {
// log_stdout("3000 Found DUCC_LD_LIBRARY_PATH and it is %s\n", envp[env_index]);
pathstr = &envp[env_index];
break;
}
}
if ( pathstr == NULL ) {
//log_stdout("3001 Did not find DUCC_LD_LIBRARY_PATH, not setting LD_LIBRARY_PATH.\n");
} else {
//
// We modify the variable in place.
//
char *val = getenv("DUCC_LD_LIBRARY_PATH");
//log_stdout("3002 Changing DUCC_LD_LIBRARY_PATH to LD_LIBRARY_PATH\n");
sprintf(*pathstr, "LD_LIBRARY_PATH=%s", val);
}
show_env(envp);
//
// Now just transmogrify into the requested command
//
log_stdout("1000 Command to exec: %s\n", argv[0]);
for ( i = 1; i < argc; i++ ) {
log_stdout(" arg[%d]: %s\n", i, argv[i]);
}
log_stdout("1001 Command launching...\n");
fflush(stdout);
fflush(stderr);
execve(argv[0], argv, envp); // just run the passed-in command
//
// if we get here it's because exec failed - it never returns if it succeeds.
//
snprintf(buf, STRLEN, "1400 cannot exec %s", argv[0]);
buf[STRLEN] = '\0';
perror(buf);
exit(1);
}