int main()

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);
}