Example #1
0
/*
 * Run a prolog or epilog script (does NOT drop privileges)
 * name IN: class of program (prolog, epilog, etc.),
 * path IN: pathname of program to run
 * job_id IN: info on associated job
 * max_wait IN: maximum time to wait in seconds, -1 for no limit
 * env IN: environment variables to use on exec, sets minimal environment
 *	if NULL
 * uid IN: user ID of job owner
 * RET 0 on success, -1 on failure.
 */
static int
_run_one_script(const char *name, const char *path, uint32_t job_id,
		int max_wait, char **env, uid_t uid)
{
	int status;
	pid_t cpid;

	xassert(env);
	if (path == NULL || path[0] == '\0')
		return 0;

	if (job_id) {
		debug("[job %u] attempting to run %s [%s]",
			job_id, name, path);
	} else
		debug("attempting to run %s [%s]", name, path);

	if (access(path, R_OK | X_OK) < 0) {
		error("Can not run %s [%s]: %m", name, path);
		return -1;
	}

	if ((cpid = fork()) < 0) {
		error ("executing %s: fork: %m", name);
		return -1;
	}
	if (cpid == 0) {
		char *argv[2];

		/* container_g_join needs to be called in the
		   forked process part of the fork to avoid a race
		   condition where if this process makes a file or
		   detacts itself from a child before we add the pid
		   to the container in the parent of the fork.
		*/
		if (container_g_join(job_id, getuid())
		    != SLURM_SUCCESS)
			error("container_g_join(%u): %m", job_id);

		argv[0] = (char *)xstrdup(path);
		argv[1] = NULL;

		setpgid(0, 0);
		execve(path, argv, env);
		error("execve(%s): %m", path);
		exit(127);
	}

	if (waitpid_timeout(name, cpid, &status, max_wait) < 0)
		return (-1);
	return status;
}
Example #2
0
/*
 * Run a prolog or epilog script (does NOT drop privileges)
 * name IN: class of program (prolog, epilog, etc.),
 * path IN: pathname of program to run
 * jobid IN: info on associated job
 * max_wait IN: maximum time to wait in seconds, -1 for no limit
 * env IN: environment variables to use on exec, sets minimal environment
 *	if NULL
 * RET 0 on success, -1 on failure.
 */
static int
run_one_script(const char *name, const char *path, uint32_t jobid,
	   int max_wait, char **env)
{
	int status;
	pid_t cpid;

	xassert(env);
	if (path == NULL || path[0] == '\0')
		return 0;

	if (jobid) {
		debug("[job %u] attempting to run %s [%s]",
			jobid, name, path);
	} else
		debug("attempting to run %s [%s]", name, path);

	if (access(path, R_OK | X_OK) < 0) {
		error("Can not run %s [%s]: %m", name, path);
		return -1;
	}

	if ((cpid = fork()) < 0) {
		error ("executing %s: fork: %m", name);
		return -1;
	}
	if (cpid == 0) {
		char *argv[2];

		argv[0] = (char *)xstrdup(path);
		argv[1] = NULL;

#ifdef SETPGRP_TWO_ARGS
		setpgrp(0, 0);
#else
		setpgrp();
#endif
		execve(path, argv, env);
		error("execve(): %m");
		exit(127);
	}

	if (waitpid_timeout(name, cpid, &status, max_wait) < 0)
		return (-1);
	return status;
}
Example #3
0
/* Poll the requested URL until a failure or timeout occurs, or until
   the child terminates on its own.  Returns 1 on HTTP failure or
   timeout, 0 on self-termination.  In either case, *status_ptr is
   filled in with the status value returned by waitpid().*/
int 
do_watchdog(int *status_ptr) {
#ifndef HAVE_LIBCURL
  fprintf(stderr, "Cannot watchdog; no libcurl available.\n");
  return 0;
#else  /* HAVE_LIBCURL */

  CURL *curl;
  CURLcode res;
  char error_buffer[CURL_ERROR_SIZE];
  pid_t wresult;

  // Before we start polling the URL, wait at least start milliseconds.
  wresult = waitpid_timeout(child_pid, status_ptr, watchdog_start_sec * 1000);
  if (wresult == child_pid) {
    // The child terminated on its own before we got started.
    return 0;
  }

  curl = curl_easy_init();
  if (!curl) {
    fprintf(stderr, "Cannot watchdog; curl failed to init.\n");
    return 0;
  }

  curl_easy_setopt(curl, CURLOPT_URL, watchdog_url);
  /*curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);*/
  curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, watchdog_timeout_sec * 1000);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, watchdog_bitbucket);
  curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
  curl_easy_setopt(curl, CURLOPT_USERAGENT, "autorestart");
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
  curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
  curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);

  res = curl_easy_perform(curl);
  while (res == 0) {
    /* 0: The HTTP request finished successfully (but might or might
       not have returned an error code like a 404). */
    long http_response = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response);
    if ((http_response / 100) != 2) {
      /* Anything in the 200 range is deemed success.  Anything else
         is deemed failure. */
      fprintf(stderr, "%s returned %ld\n", watchdog_url, http_response);
      break;
    }

    wresult = waitpid_timeout(child_pid, status_ptr, watchdog_cycle_sec * 1000);
    if (wresult == child_pid) {
      /* The process terminated on its own.  Return 0 to indicate this. */
      return 0;
    }

    res = curl_easy_perform(curl);
  }

  curl_easy_cleanup(curl);

  /* Failed to retrieve the watchdog URL. */
  if (res != 0) {
    fprintf(stderr, "Failed to contact %s: %s\n", watchdog_url, error_buffer);
  }
  
  /* Kill the child process and wait for it to go away. */
  kill(child_pid, SIGTERM);

  pid_t result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000);
  if (result != child_pid) {
    if (result == -1) {
      perror("waitpid");
    } else {
      /* SIGTERM didn't make the process die.  Try SIGKILL. */
      fprintf(stderr, "Force-killing child process\n");
      kill(child_pid, SIGKILL);
      result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000);
      if (result == -1) {
        perror("waitpid");
      }
    }
  }

  /* Return 1 to indicate we killed the child due to an HTTP error. */
  return 1;
#endif  /* HAVE_LIBCURL */
}
Example #4
0
PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh,
                                   int flags, int argc, const char **argv)
{

    const char *user = NULL, *passwd = NULL;
    struct passwd *pwd;
    int rval, status;
    pid_t pid;


    // For checking mount paths: (mount from + target)
    char path[PATH_MAX];
    char targetpath[PATH_MAX];
    char encfs_options[USERNAME_MAX];
    char fuse_options[USERNAME_MAX];
    char *targetpath_store;

    strcpy(default_encfs_options, "");
    strcpy(default_fuse_options, "");

    // For execing:
    char *arg[USERNAME_MAX];
    int arg_pos = 0;
    int i;
    int inpipe[2], outpipe[2];

    rval = pam_get_user(pamh, &user, NULL);
    if ((rval != PAM_SUCCESS) || (!user))
    {
        _pam_log(LOG_ERR, "can't get username: %s", pam_strerror(pamh, rval));
        return PAM_AUTH_ERR;
    }

    rval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd);
    if (rval != PAM_SUCCESS)
    {
        _pam_log(LOG_ERR, "Could not retrieve user's password");
        return PAM_AUTH_ERR;
    }

    if (!passwd)
    {
        rval = _set_auth_tok(pamh, flags, argc, argv);
        if (rval != PAM_SUCCESS)
        {
            return rval;
        }
        rval =
            pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd);
        if (rval != PAM_SUCCESS || passwd == NULL)
        {
            _pam_log(LOG_ERR, "Could not retrieve user's password");
            return PAM_AUTH_ERR;
        }
    }
    if ((pwd = getpwnam(user)) == NULL)
    {
        _pam_log(LOG_ERR, "Could not getpwnam");
        return PAM_AUTH_ERR;
    }

    // Read configfile  
    if (!readconfig
        (pwd, pamh, pwd->pw_name, path, targetpath, encfs_options,
         fuse_options))
    {
        // DEBUG _pam_log(LOG_ERR,"No entry for user found in log");
        return PAM_IGNORE;
    }
    //DEBUG _pam_log(LOG_ERR,"Username : %s, Encpath : %s, Targetmount : %s",pwd->pw_name,path,targetpath);

    //Store targetpath
    targetpath_store = strdup(targetpath);
    if ((i =
         pam_set_data(pamh, "encfs_targetpath", targetpath_store,
                      targetpath_cleanup)) != PAM_SUCCESS)
    {
        _pam_log(LOG_ERR, "Storing targetpath FAIL");
        free(targetpath_store);
        return i;
    }

    // Check if we're mounted already.
    if (checkmnt(targetpath))
    {
        //DEBUG _pam_log(LOG_ERR,"Already mounted");
        return PAM_IGNORE;
    }



    /*  _pam_log(LOG_ERR,"Config output for %s:",user);
       _pam_log(LOG_ERR,"  path       : %s",path);
       _pam_log(LOG_ERR,"  targetpath : %s",targetpath);
       _pam_log(LOG_ERR,"  encfs      : %s %s",default_encfs_options,encfs_options);
       _pam_log(LOG_ERR,"  fuse       : %s %s",default_fuse_options,fuse_options); */


    arg_pos += buildCmd(arg, arg_pos, "encfs");
    arg_pos += buildCmd(arg, arg_pos, "-S");
    arg_pos += buildCmd(arg, arg_pos, default_encfs_options);
    arg_pos += buildCmd(arg, arg_pos, encfs_options);
    arg_pos += buildCmd(arg, arg_pos, path);
    arg_pos += buildCmd(arg, arg_pos, targetpath);

    if (strlen(default_fuse_options) > 0 && strlen(fuse_options) > 0)
        strcat(fuse_options, ",");

    strcat(fuse_options,default_fuse_options);
    if (strlen(fuse_options) > 0) {
        arg_pos += buildCmd(arg, arg_pos, "--");
        arg_pos += buildCmd(arg, arg_pos, "-o");
        arg_pos += buildCmd(arg, arg_pos, fuse_options);
    }
    arg[arg_pos] = NULL;

    /*  printf("Arguments : ");
       for (i = 0; i < arg_pos+1;i++) {
       _pam_log(LOG_ERR,"Data : %s",arg[i]);
       }

       _pam_log(LOG_ERR,"Number of arguments : %d",arg_pos); */


    /*  arg[0] = cmd;
       arg[1] = params;
       //  arg[2] = params2;
       arg[2] = params3;
       arg[3] = path;
       arg[4] = targetpath;
       arg[5] = fuseparams;
       arg[6] = fuseparams2;
       arg[7] = NULL; */



    if (pipe(inpipe) || pipe(outpipe))
    {
        _pam_log(LOG_ERR, "Failed to create pipe");
        return PAM_IGNORE;
    }

    // Execute 
    switch (pid = fork())
    {
        case -1:
            _pam_log(LOG_ERR, "Fork failed");
            return PAM_SERVICE_ERR;
        case 0:

            if (drop_permissions == 1)
                if ((initgroups(pwd->pw_name, pwd->pw_gid) == -1)
                    || (setgid(pwd->pw_gid) == -1)
                    || (setuid(pwd->pw_uid) == -1))
                {
                    _pam_log(LOG_ERR, "Dropping permissions failed");
                    return PAM_SERVICE_ERR;
                }
            close(outpipe[WRITE_END]);
            dup2(outpipe[READ_END], fileno(stdin));
            close(outpipe[READ_END]);

            close(inpipe[READ_END]);
            dup2(inpipe[WRITE_END], fileno(stdout));
            close(inpipe[WRITE_END]);

            // For some reason the current directory has to be set to targetpath (or path?) before exec'ing encfs through gdm
            chdir(targetpath);
            execvp("encfs", arg);
            char errstr[128];

            snprintf(errstr, 127, "%d - %s", errno, strerror(errno));
            _pam_log(LOG_ERR, "Exec failed - %s", errstr);
            exit(127);
    }

    int len;


    close(inpipe[WRITE_END]);
    close(outpipe[READ_END]);




    if (waitpid(pid, &status, WNOHANG) == 0)
    {
        len = write(outpipe[WRITE_END], passwd, (size_t) strlen(passwd));
        if ((len != (size_t) strlen(passwd))
            || (write(outpipe[WRITE_END], "\n", 1) != 1))
            _pam_log(LOG_ERR, "Did not send password to pipe (%d sent)", len);
        close(outpipe[WRITE_END]);
    }


    if (waitpid_timeout(pid, &status, 0))
    {
        _pam_log(LOG_ERR, "Timed out waiting for encfs, killing\n");
        kill(pid, SIGKILL);
    }

    int exitstatus = WEXITSTATUS(status);
    char buff[512];

    len = read(inpipe[READ_END], &buff, 511);
    close(inpipe[READ_END]);
    buff[len] = 0;
    if (!checkmnt(targetpath) && (len > 0 || exitstatus > 0))
    {
        _pam_log(LOG_ERR, "exitcode : %d, errorstring : %s", exitstatus,
                 buff);
        return PAM_AUTH_ERR;
    }
    else
    {
        return PAM_IGNORE;
    }
    return PAM_AUTH_ERR;
}