/** * Write the pid of the current process to the cgroup file. * cgroup_file: Path to cgroup file where pid needs to be written to. */ static int write_pid_to_cgroup_as_root(const char* cgroup_file, pid_t pid) { uid_t user = geteuid(); gid_t group = getegid(); if (change_effective_user(0, 0) != 0) { return -1; } // open int cgroup_fd = open(cgroup_file, O_WRONLY | O_APPEND, 0); if (cgroup_fd == -1) { fprintf(LOGFILE, "Can't open file %s as node manager - %s\n", cgroup_file, strerror(errno)); return -1; } // write pid char pid_buf[21]; snprintf(pid_buf, sizeof(pid_buf), "%d", pid); ssize_t written = write(cgroup_fd, pid_buf, strlen(pid_buf)); close(cgroup_fd); if (written == -1) { fprintf(LOGFILE, "Failed to write pid to file %s - %s\n", cgroup_file, strerror(errno)); return -1; } // Revert back to the calling user. if (change_effective_user(user, group)) { return -1; } return 0; }
/** * Create a top level directory for the user. * It assumes that the parent directory is *not* writable by the user. * It creates directories with 02750 permissions owned by the user * and with the group set to the task tracker group. * return non-0 on failure */ int create_directory_for_user(const char* path) { // set 2750 permissions and group sticky bit mode_t permissions = S_IRWXU | S_IRGRP | S_IXGRP | S_ISGID; uid_t user = geteuid(); gid_t group = getegid(); int ret = 0; uid_t root = 0; //This check is particularly required for c-based unit tests since //tests run as a regular user. if (getuid() == root) { ret = change_effective_user(root, tt_gid); } if (ret == 0) { if (mkdir(path, permissions) == 0 || errno == EEXIST) { // need to reassert the group sticky bit if (chmod(path, permissions) != 0) { fprintf(LOGFILE, "Can't chmod %s to add the sticky bit - %s\n", path, strerror(errno)); ret = -1; } else if (change_owner(path, user, tt_gid) != 0) { ret = -1; } } else { fprintf(LOGFILE, "Failed to create directory %s - %s\n", path, strerror(errno)); ret = -1; } } if (change_effective_user(user, group) != 0) { ret = -1; } return ret; }
/** * Write the pid of the current process into the pid file. * pid_file: Path to pid file where pid needs to be written to */ static int write_pid_to_file_as_nm(const char* pid_file, pid_t pid) { uid_t user = geteuid(); gid_t group = getegid(); if (change_effective_user(nm_uid, nm_gid) != 0) { return -1; } char *temp_pid_file = concatenate("%s.tmp", "pid_file_path", 1, pid_file); // create with 700 int pid_fd = open(temp_pid_file, O_WRONLY|O_CREAT|O_EXCL, S_IRWXU); if (pid_fd == -1) { fprintf(LOGFILE, "Can't open file %s as node manager - %s\n", temp_pid_file, strerror(errno)); free(temp_pid_file); return -1; } // write pid to temp file char pid_buf[21]; snprintf(pid_buf, 21, "%d", pid); ssize_t written = write(pid_fd, pid_buf, strlen(pid_buf)); close(pid_fd); if (written == -1) { fprintf(LOGFILE, "Failed to write pid to file %s as node manager - %s\n", temp_pid_file, strerror(errno)); free(temp_pid_file); return -1; } // rename temp file to actual pid file // use rename as atomic if (rename(temp_pid_file, pid_file)) { fprintf(LOGFILE, "Can't move pid file from %s to %s as node manager - %s\n", temp_pid_file, pid_file, strerror(errno)); unlink(temp_pid_file); free(temp_pid_file); return -1; } // Revert back to the calling user. if (change_effective_user(user, group)) { free(temp_pid_file); return -1; } free(temp_pid_file); return 0; }
/** * Delete a final directory as the task tracker user. */ static int rmdir_as_tasktracker(const char* path) { int user_uid = geteuid(); int user_gid = getegid(); int ret = change_effective_user(tt_uid, tt_gid); if (ret == 0) { if (rmdir(path) != 0) { fprintf(LOGFILE, "rmdir of %s failed - %s\n", path, strerror(errno)); ret = -1; } } // always change back if (change_effective_user(user_uid, user_gid) != 0) { ret = -1; } return ret; }
/** * Open a file as the tasktracker and return a file descriptor for it. * Returns -1 on error */ static int open_file_as_task_tracker(const char* filename) { uid_t user = geteuid(); gid_t group = getegid(); if (change_effective_user(tt_uid, tt_gid) != 0) { return -1; } int result = open(filename, O_RDONLY); if (result == -1) { fprintf(LOGFILE, "Can't open file %s as task tracker - %s\n", filename, strerror(errno)); } if (change_effective_user(user, group)) { result = -1; } return result; }
/** * Wait for the container process to exit and write the exit code to * the exit code file. * Returns the exit code of the container process. */ static int wait_and_write_exit_code(pid_t pid, const char* exit_code_file) { int child_status = -1; int exit_code = -1; int waitpid_result; if (change_effective_user(nm_uid, nm_gid) != 0) { return -1; } do { waitpid_result = waitpid(pid, &child_status, 0); } while (waitpid_result == -1 && errno == EINTR); if (waitpid_result < 0) { fprintf(LOGFILE, "Error waiting for container process %d - %s\n", pid, strerror(errno)); return -1; } if (WIFEXITED(child_status)) { exit_code = WEXITSTATUS(child_status); } else if (WIFSIGNALED(child_status)) { exit_code = 0x80 + WTERMSIG(child_status); } else { fprintf(LOGFILE, "Unable to determine exit status for pid %d\n", pid); } if (write_exit_code_file(exit_code_file, exit_code) < 0) { return -1; } return exit_code; }
/** * Change the ownership of the given file or directory to the new user. */ static int change_owner(const char* path, uid_t user, gid_t group) { if (geteuid() == user && getegid() == group) { return 0; } else { uid_t old_user = geteuid(); gid_t old_group = getegid(); if (change_effective_user(0, group) != 0) { return -1; } if (chown(path, user, group) != 0) { fprintf(LOGFILE, "Can't chown %s to %d:%d - %s\n", path, user, group, strerror(errno)); return -1; } return change_effective_user(old_user, old_group); } }
/** * Create a top level directory for the user. * It assumes that the parent directory is *not* writable by the user. * It creates directories with 02700 permissions owned by the user * and with the group set to the task tracker group. * return non-0 on failure */ int create_directory_for_user(const char* path) { // set 2750 permissions and group sticky bit mode_t permissions = S_IRWXU | S_IRGRP | S_IXGRP | S_ISGID; uid_t user = geteuid(); gid_t group = getegid(); int ret = 0; ret = change_effective_user(tt_uid, tt_gid); if (ret == 0) { if (mkdir(path, permissions) == 0) { // need to reassert the group sticky bit if (chmod(path, permissions) != 0) { fprintf(LOGFILE, "Can't chmod %s to add the sticky bit - %s\n", path, strerror(errno)); ret = -1; } else if (change_owner(path, user, tt_gid) != 0) { ret = -1; } } else if (errno == EEXIST) { struct stat file_stat; if (stat(path, &file_stat) != 0) { fprintf(LOGFILE, "Can't stat directory %s - %s\n", path, strerror(errno)); ret = -1; } else { if (file_stat.st_uid != user || file_stat.st_gid != tt_gid) { fprintf(LOGFILE, "Directory %s owned by wrong user or group. " "Expected %d:%d and found %d:%d.\n", path, user, tt_gid, file_stat.st_uid, file_stat.st_gid); ret = -1; } } } else { fprintf(LOGFILE, "Failed to create directory %s - %s\n", path, strerror(errno)); ret = -1; } } if (change_effective_user(user, group) != 0) { ret = -1; } return ret; }
/** * function used to populate and user_details structure. */ int set_user(const char *user) { // free any old user if (user_detail != NULL) { free(user_detail); user_detail = NULL; } user_detail = check_user(user); if (user_detail == NULL) { return -1; } return change_effective_user(user_detail->pw_uid, user_detail->pw_gid); }
/** * Create a top level directory for the user. * It assumes that the parent directory is *not* writable by the user. * It creates directories with 02750 permissions owned by the user * and with the group set to the node manager group. * return non-0 on failure */ int create_directory_for_user(const char* path) { // set 2750 permissions and group sticky bit mode_t permissions = S_IRWXU | S_IRGRP | S_IXGRP | S_ISGID; uid_t user = geteuid(); gid_t group = getegid(); uid_t root = 0; int ret = 0; if(getuid() == root) { ret = change_effective_user(root, nm_gid); } if (ret == 0) { if (0 == mkdir(path, permissions) || EEXIST == errno) { // need to reassert the group sticky bit if (chmod(path, permissions) != 0) { fprintf(LOGFILE, "Can't chmod %s to add the sticky bit - %s\n", path, strerror(errno)); ret = -1; } else if (change_owner(path, user, nm_gid) != 0) { fprintf(LOGFILE, "Failed to chown %s to %d:%d: %s\n", path, user, nm_gid, strerror(errno)); ret = -1; } } else { fprintf(LOGFILE, "Failed to create directory %s - %s\n", path, strerror(errno)); ret = -1; } } if (change_effective_user(user, group) != 0) { fprintf(LOGFILE, "Failed to change user to %i - %i\n", user, group); ret = -1; } return ret; }
/** * function used to populate and user_details structure. */ int set_user(const char *user) { // free any old user if (user_detail != NULL) { free(user_detail); user_detail = NULL; } user_detail = check_user(user); if (user_detail == NULL) { return -1; } if (geteuid() == user_detail->pw_uid) { return 0; } if (initgroups(user, user_detail->pw_gid) != 0) { fprintf(LOGFILE, "Error setting supplementary groups for user %s: %s\n", user, strerror(errno)); return -1; } return change_effective_user(user_detail->pw_uid, user_detail->pw_gid); }