static int PCS_Stream_close(php_stream *stream, int close_handle TSRMLS_DC) { PCS_STREAM_DATA *dp = stream->abstract; free_dp(&dp); return 0; }
/* Remove the user with matching user and group name and * remove all her transactions from the transaction list. * Return 0 on success, and -1 if no matching user exists. * Remember to free memory no longer needed. * (Wait on implementing the removal of the user's transactions until you * get to Part III below, when you will implement transactions.) */ int remove_user(Group *group, const char *user_name) { /* Gets the previous user before the user to be deleted if the to be deleted * user is not a head. If the to be deleted user is a head, the to be deleted * is returned. If the user doesn't exist in the group, NULL is returned. */ User *prev_user = find_prev_user(group, user_name); /* If the user returned is not NULL, this means that user exists in the group, * therefore we check if the returned user is a head or the previous user. * 1) If it is a previous user, we set the previous user next pointer to * the next next user and free space for the deleted user. */ if (prev_user != NULL) { if (strcmp(prev_user->name, user_name) == 0) { group->users = prev_user->next; remove_xct(group, user_name); free_dp(prev_user->name); free_dp(prev_user); return 0; /* 2) If it is a head node, we reset the head to the next user and free * up space for the deleted node. Free space for the user name * and the user, also points the user to NULL to avoid dangling * pointers. */ } else if (strcmp(prev_user->next->name, user_name) == 0) { User *temp = prev_user->next; prev_user->next = prev_user->next->next; remove_xct(group, user_name); free_dp(temp->name); free_dp(temp); } // Return 0 if we the deletion is successful. return 0; /* If the user returned is NULL, that means the user name doesn't exist, no * users are deleted, and -1 is returned. */ } else { return -1; } }
int do_exec(char *path, char **argv, char **env, int shebanged /* oh my */) { unsigned int i=0; addr_t end, eip; unsigned int argc=0, envc=0; char **backup_argv=0, **backup_env=0; /* Sanity */ if(!path || !*path) return -EINVAL; /* Load the file, and make sure that it is valid and accessible */ if(EXEC_LOG == 2) printk(0, "[%d]: Checking executable file (%s)\n", current_process->pid, path); struct file *efil; int err_open; efil = fs_file_open(path, _FREAD, 0, &err_open); if(!efil) return err_open; /* are we allowed to execute it? */ if(!vfs_inode_check_permissions(efil->inode, MAY_EXEC, 0)) { file_put(efil); return -EACCES; } /* is it a valid elf? */ int header_size = 0; #if CONFIG_ARCH == TYPE_ARCH_X86_64 header_size = sizeof(elf64_header_t); #elif CONFIG_ARCH == TYPE_ARCH_X86 header_size = sizeof(elf32_header_t); #endif /* read in the ELF header, and check if it's a shebang */ if(header_size < 2) header_size = 2; unsigned char mem[header_size]; fs_file_pread(efil, 0, mem, header_size); if(__is_shebang(mem)) return loader_do_shebang(efil, argv, env); int other_bitsize=0; if(!is_valid_elf(mem, 2) && !other_bitsize) { file_put(efil); return -ENOEXEC; } if(EXEC_LOG == 2) printk(0, "[%d]: Copy data\n", current_process->pid); /* okay, lets back up argv and env so that we can * clear out the address space and not lose data... * If this call if coming from a shebang, then we don't check the pointers, * since they won't be from userspace */ size_t total_args_len = 0; if((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, argv, 0)) && argv) { while((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, argv[argc], 0)) && argv[argc] && *argv[argc]) argc++; backup_argv = (char **)kmalloc(sizeof(addr_t) * argc); for(i=0;i<argc;i++) { backup_argv[i] = (char *)kmalloc(strlen(argv[i]) + 1); _strcpy(backup_argv[i], argv[i]); total_args_len += strlen(argv[i])+1 + sizeof(char *); } } if((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, env, 0)) && env) { while((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, env[envc], 0)) && env[envc] && *env[envc]) envc++; backup_env = (char **)kmalloc(sizeof(addr_t) * envc); for(i=0;i<envc;i++) { backup_env[i] = (char *)kmalloc(strlen(env[i]) + 1); _strcpy(backup_env[i], env[i]); total_args_len += strlen(env[i])+1 + sizeof(char *); } } total_args_len += 2 * sizeof(char *); /* and the path too! */ char *path_backup = (char *)kmalloc(strlen(path) + 1); _strcpy((char *)path_backup, path); path = path_backup; /* Preexec - This is the point of no return. Here we close out unneeded * file descs, free up the page directory and clear up the resources * of the task */ if(EXEC_LOG) printk(0, "Executing (p%dt%d, cpu %d, tty %d): %s\n", current_process->pid, current_thread->tid, current_thread->cpu->knum, current_process->pty ? current_process->pty->num : 0, path); preexec(); /* load in the new image */ strncpy((char *)current_process->command, path, 128); if(!loader_parse_elf_executable(mem, efil, &eip, &end)) eip=0; /* do setuid and setgid */ if(efil->inode->mode & S_ISUID) { current_process->effective_uid = efil->inode->uid; } if(efil->inode->mode & S_ISGID) { current_process->effective_gid = efil->inode->gid; } /* we don't need the file anymore, close it out */ file_put(efil); file_close_cloexec(); if(!eip) { printk(5, "[exec]: Tried to execute an invalid ELF file!\n"); free_dp(backup_argv, argc); free_dp(backup_env, envc); kfree(path); tm_thread_exit(0); } if(EXEC_LOG == 2) printk(0, "[%d]: Updating task values\n", current_process->pid); /* Setup the task with the proper values (libc malloc stack) */ addr_t end_l = end; end = ((end-1)&PAGE_MASK) + PAGE_SIZE; total_args_len += PAGE_SIZE; /* now we need to copy back the args and env into userspace * writeable memory...yippie. */ addr_t args_start = end + PAGE_SIZE; addr_t env_start = args_start; addr_t alen = 0; mm_mmap(end, total_args_len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, 0); if(backup_argv) { memcpy((void *)args_start, backup_argv, sizeof(addr_t) * argc); alen += sizeof(addr_t) * argc; *(addr_t *)(args_start + alen) = 0; /* set last argument value to zero */ alen += sizeof(addr_t); argv = (char **)args_start; for(i=0;i<argc;i++) { char *old = argv[i]; char *new = (char *)(args_start+alen); unsigned len = strlen(old) + 4; argv[i] = new; _strcpy(new, old); kfree(old); alen += len; } kfree(backup_argv); } env_start = args_start + alen; alen = 0; if(backup_env) { memcpy((void *)env_start, backup_env, sizeof(addr_t) * envc); alen += sizeof(addr_t) * envc; *(addr_t *)(env_start + alen) = 0; /* set last argument value to zero */ alen += sizeof(addr_t); env = (char **)env_start; for(i=0;i<envc;i++) { char *old = env[i]; char *new = (char *)(env_start+alen); unsigned len = strlen(old) + 1; env[i] = new; _strcpy(new, old); kfree(old); alen += len; } kfree(backup_env); } end = (env_start + alen) & PAGE_MASK; current_process->env = env; current_process->argv = argv; kfree(path); /* set the heap locations, and map in the start */ current_process->heap_start = current_process->heap_end = end + PAGE_SIZE*2; addr_t ret = mm_mmap(end + PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, 0); /* now, we just need to deal with the syscall return stuff. When the syscall * returns, it'll just jump into the entry point of the new process */ tm_thread_lower_flag(current_thread, THREAD_SCHEDULE); /* the kernel cares if it has executed something or not */ if(!(kernel_state_flags & KSF_HAVEEXECED)) set_ksf(KSF_HAVEEXECED); arch_loader_exec_initializer(argc, eip); if(EXEC_LOG == 2) printk(0, "[%d]: Performing call\n", current_process->pid); return 0; }
/* Remove all transactions that belong to the user_name from the group's * transaction list. This helper function should be called by remove_user. * If there are no transactions for this user, the function should do nothing. * Remember to free memory no longer needed. */ void remove_xct(Group *group, const char *user_name) { /* Initializes a pointer to the first node of the xct list in order to traverse * through the list to find the list to find the correct xct to be deleted. */ Xct *curr = group->xcts; /* Checks if the head of the xct list matches the user name that should be * deleted from xcts. After deletion, it frees memory that is no longer needed * by the pointer and points to NULL to avoid dangling pointers. */ while (strcmp(curr->name, user_name) == 0) { Xct *tmp = curr; if (curr->next == NULL) { group->xcts = NULL; curr = group->xcts; free_dp(tmp->name); free_dp(tmp); return; } else { group->xcts = curr->next; curr = group->xcts; free_dp(tmp->name); free_dp(tmp); } } /* Traverses through the rest of the xct list to find other xct nodes to * delete if any. The xct node is deleted and then the memory is freed and * the pointer is pointed to NULL to avoid dangling pointer. */ if (curr != NULL) { while (curr != NULL && curr->next != NULL) { if (strcmp(curr->next->name, user_name) == 0) { Xct *tmp = curr->next; /* Checks if next is NULL, if it is NULL, it means that the end of * of the list have been reached and the last xct should be deleted. */ if (tmp->next == NULL) { curr->next = NULL; /* If the next is not NULL, current next pointer is set to the xct * after tmp. */ } else { curr->next = curr->next->next; } free_dp(tmp->name); free_dp(tmp); } /* Checks if next xct after current is NULL, if the current is NULL we * can check for the name of the xct. */ if (curr->next != NULL) { if (strcmp(curr->next->name, user_name) != 0) { curr = curr->next; } } } } }
/* Add the transaction represented by user_name and amount to the appropriate * transaction list, and update the balances of the corresponding user and group. * Note that updating a user's balance might require the user to be moved to a * different position in the list to keep the list in sorted order. Returns 0 on * success, and -1 if the specified user does not exist. */ int add_xct(Group *group, const char *user_name, double amount) { /* Allocate space for the new xct that is to be added to the list of * xcts. */ Xct *new_xct = (Xct*) malloc (sizeof(Xct)); /* Checks if malloc failed, if malloc failed, a error message is printed to * standard output and exit code of 256. */ if (new_xct == NULL) { print_exit("ERROR: Malloc failed", 256); /* If malloc didn't fail, the user name and the amount is assigned to the new * xct and the next pointer is set to NULL temporarily. */ } else { int size_to_malloc = (strlen(user_name)+1)*sizeof(char); new_xct->name = (char*) malloc (size_to_malloc); /* Checks if the current malloc failed, if it failed a message is printed * to standard output and exit code of 256 is set. */ if (new_xct->name == NULL) { print_exit("ERROR: Malloc failed", 256); } strncpy(new_xct->name, user_name, size_to_malloc); new_xct->name[size_to_malloc] = '\0'; new_xct->amount = amount; new_xct->next = NULL; } /* Finds the previous user to the user that added a xct in order to change * the user's balance and re-organize the list. */ User *prev_user = find_prev_user(group, user_name); /* If no user was found with the same user name in the list of users, -1 is * returned. */ if (prev_user == NULL) { free_dp(new_xct->name); free_dp(new_xct); return -1; /* Checks if the user returned is the head of the list of users, if it is, * the head is changed so that the user can be moved to its correct location. */ } else if (strcmp(prev_user->name, user_name) == 0) { push_xct(group, new_xct); prev_user->balance += amount; sort_user(group, prev_user, user_name); return 0; /* Checks if the user returned is in the middle of the list of users, the * user is remvoed from its current position and placed in the correct * position in the users of list. */ } else { push_xct(group, new_xct); prev_user->next->balance += amount; sort_user(group, prev_user, user_name); return 0; } }
/* Add a group with name group_name to the group_list referred to by * group_list_ptr. The groups are ordered by the time that the group was * added to the list with new groups added to the end of the list. * * Returns 0 on success and -1 if a group with this name already exists. * * (I.e, allocate and initialize a Group struct, and insert it * into the group_list. Note that the head of the group list might change * which is why the first argument is a double pointer.) */ int add_group(Group **group_list_ptr, const char *group_name) { /* Allocates space in memory for new_group in order to add the group the * group_list */ Group *new_group = (Group*) malloc (sizeof(Group)); /* Checks if malloc have allocated space. * 1) If it didn't, print out error message and exit with code 256 */ if (new_group == NULL) { print_exit("ERROR: Malloc failed", 256); /* 2) If it did, set the new group_name, set users, xcts and next pointers * to NULL */ } else { int size_to_malloc = (strlen(group_name) + 1) * sizeof(char); new_group->name = (char*) malloc (size_to_malloc); /* Checks if malloc completed successfully, if it didn't complete * successfully it will print out an error message to standard output. */ if (new_group->name == NULL) { print_exit("ERROR: Malloc failed", 256); } strncpy(new_group->name, group_name, size_to_malloc); new_group->name[size_to_malloc] = '\0'; /* All other pointers are set NULL until the embedded linked list are * declared and initialized. */ new_group->users = NULL; new_group->xcts = NULL; new_group->next = NULL; } /* Checks if the list is empty. * If it is, it sets the new_group to the head of the list and 0 is returned */ if (*group_list_ptr == NULL) { *group_list_ptr = new_group; return 0; /* If it is not an empty list, it will traverse the list to detect if a group * with the same name already exists. */ } else { Group *curr = *group_list_ptr; while (curr != NULL) { /* Compares the current group name with the group_name (user wants * to add). * 1) If a group with the same name exists, -1 is returned */ if (strcmp(curr->name, group_name) == 0) { free_dp(new_group->name); free_dp(new_group); return -1; } else if (curr->next == NULL) { curr->next = new_group; return 0; } else { curr = curr->next; } } return 0; } }
void free_user_xct(void *in_ptr, void *main_ptr) { free_dp(in_ptr); free_dp(main_ptr); }
/* Add a new user with the specified user name to the specified group. Return zero * on success and -1 if the group already has a user with that name. * (allocate and initialize a User data structure and insert it into the * appropriate group list) */ int add_user(Group *group, const char *user_name) { /* Allocates space in memory for the user, and checks if malloc has been * completed successfully. */ User *new_user = (User*) malloc (sizeof(User)); /* If malloc is not completed succesfully, an error message will be printed * out to standard output and program will exit with 256 exit code */ if (new_user == NULL) { print_exit("ERROR: Malloc failed", 256); /* If malloc has been completed successfully, the user name is set to user_name * and set initial balance to 0 */ } else { int size_to_malloc = (strlen(user_name)+1)*sizeof(char); new_user->name = (char*) malloc (size_to_malloc); /* Checks if malloc is completed succesfully, if it is not completed * successfully, and error message will be printed out the screen and exit * code of 256. */ if (new_user->name == NULL) { print_exit("ERROR: Malloc failed", 256); } /* Copies the user_name given to the user name got the newly created * user. */ strncpy(new_user->name, user_name, size_to_malloc); new_user->name[size_to_malloc] = '\0'; /* Sets all other values to either 0.0 if it is double, or NULL if it is * a pointer to another linked list. */ new_user->balance = 0.0; new_user->next = NULL; } // Returns the user if the user already exists in the group. User *prev_user = find_prev_user(group, user_name); /* If prev_user is NULL, meaning no user in the group exists with the same * name. We can add the new user in this case to the specified group. */ if (prev_user == NULL) { prev_user = new_user; User *tmp = group->users; group->users = prev_user; group->users->next = tmp; return 0; /* If prev_user is not NULL, this means that a user with the same name already * exists, so we don't add the new user and just return -1. Free space for * the user name and the user, also points the user to NULL to avoid dangling * pointers */ } else { free_dp(new_user->name); free_dp(new_user); return -1; } }
int do_exec(task_t *t, char *path, char **argv, char **env) { unsigned int i=0; addr_t end, eip; unsigned int argc=0, envc=0; int desc; char **backup_argv=0, **backup_env=0; /* Sanity */ if(!t) panic(PANIC_NOSYNC, "Tried to execute with empty task"); if(t == kernel_task) panic(0, "Kernel is being executed at the gallows!"); if(t != current_task) panic(0, "I don't know, was really drunk at the time"); if(t->magic != TASK_MAGIC) panic(0, "Invalid task in exec (%d)", t->pid); if(!path || !*path) return -EINVAL; /* Load the file, and make sure that it is valid and accessable */ if(EXEC_LOG == 2) printk(0, "[%d]: Checking executable file (%s)\n", t->pid, path); struct file *efil; int err_open, num; efil=d_sys_open(path, O_RDONLY, 0, &err_open, &num); if(efil) desc = num; else desc = err_open; if(desc < 0 || !efil) return -ENOENT; if(!permissions(efil->inode, MAY_EXEC)) { sys_close(desc); return -EACCES; } /* Detirmine if the file is a valid ELF */ int header_size = 0; #if CONFIG_ARCH == TYPE_ARCH_X86_64 header_size = sizeof(elf64_header_t); #elif CONFIG_ARCH == TYPE_ARCH_X86 header_size = sizeof(elf32_header_t); #endif char mem[header_size]; read_data(desc, mem, 0, header_size); int other_bitsize=0; #if CONFIG_ARCH == TYPE_ARCH_X86_64 if(is_valid_elf32_otherarch(mem, 2)) other_bitsize = 1; #endif if(!is_valid_elf(mem, 2) && !other_bitsize) { sys_close(desc); return -ENOEXEC; } if(EXEC_LOG == 2) printk(0, "[%d]: Copy data\n", t->pid); /* okay, lets back up argv and env so that we can * clear out the address space and not lose data..*/ if(__is_valid_user_ptr(SYS_EXECVE, argv, 0)) { while(__is_valid_user_ptr(SYS_EXECVE, argv[argc], 0) && *argv[argc]) argc++; backup_argv = (char **)kmalloc(sizeof(addr_t) * argc); for(i=0;i<argc;i++) { backup_argv[i] = (char *)kmalloc(strlen(argv[i]) + 1); _strcpy(backup_argv[i], argv[i]); } } if(__is_valid_user_ptr(SYS_EXECVE, env, 0)) { while(__is_valid_user_ptr(SYS_EXECVE, env[envc], 0) && *env[envc]) envc++; backup_env = (char **)kmalloc(sizeof(addr_t) * envc); for(i=0;i<envc;i++) { backup_env[i] = (char *)kmalloc(strlen(env[i]) + 1); _strcpy(backup_env[i], env[i]); } } /* and the path too! */ char *path_backup = (char *)kmalloc(strlen(path) + 1); _strcpy((char *)path_backup, path); path = path_backup; if(pd_cur_data->count > 1) printk(0, "[exec]: Not sure what to do here...\n"); /* Preexec - This is the point of no return. Here we close out unneeded * file descs, free up the page directory and clear up the resources * of the task */ if(EXEC_LOG) printk(0, "Executing (task %d, cpu %d, tty %d, cwd=%s): %s\n", t->pid, ((cpu_t *)t->cpu)->apicid, t->tty, current_task->thread->pwd->name, path); preexec(t, desc); strncpy((char *)t->command, path, 128); if(other_bitsize) { #if CONFIG_ARCH == TYPE_ARCH_X86_64 if(!process_elf_other(mem, desc, &eip, &end)) eip=0; #endif } else if(!process_elf(mem, desc, &eip, &end)) eip=0; sys_close(desc); if(!eip) { printk(5, "[exec]: Tried to execute an invalid ELF file!\n"); free_dp(backup_argv, argc); free_dp(backup_env, envc); #if DEBUG panic(0, ""); #endif exit(0); } if(EXEC_LOG == 2) printk(0, "[%d]: Updating task values\n", t->pid); /* Setup the task with the proper values (libc malloc stack) */ addr_t end_l = end; end = (end&PAGE_MASK); user_map_if_not_mapped_noclear(end); /* now we need to copy back the args and env into userspace * writeable memory...yippie. */ addr_t args_start = end + PAGE_SIZE; addr_t env_start = args_start; addr_t alen = 0; if(backup_argv) { for(i=0;i<(sizeof(addr_t) * (argc+1))/PAGE_SIZE + 2;i++) user_map_if_not_mapped_noclear(args_start + i * PAGE_SIZE); memcpy((void *)args_start, backup_argv, sizeof(addr_t) * argc); alen += sizeof(addr_t) * argc; *(addr_t *)(args_start + alen) = 0; /* set last argument value to zero */ alen += sizeof(addr_t); argv = (char **)args_start; for(i=0;i<argc;i++) { char *old = argv[i]; char *new = (char *)(args_start+alen); user_map_if_not_mapped_noclear((addr_t)new); unsigned len = strlen(old) + 4; user_map_if_not_mapped_noclear((addr_t)new + len + 1); argv[i] = new; _strcpy(new, old); kfree(old); alen += len; } kfree(backup_argv); } env_start = args_start + alen; alen = 0; if(backup_env) { for(i=0;i<(((sizeof(addr_t) * (envc+1))/PAGE_SIZE) + 2);i++) user_map_if_not_mapped_noclear(env_start + i * PAGE_SIZE); memcpy((void *)env_start, backup_env, sizeof(addr_t) * envc); alen += sizeof(addr_t) * envc; *(addr_t *)(env_start + alen) = 0; /* set last argument value to zero */ alen += sizeof(addr_t); env = (char **)env_start; for(i=0;i<envc;i++) { char *old = env[i]; char *new = (char *)(env_start+alen); user_map_if_not_mapped_noclear((addr_t)new); unsigned len = strlen(old) + 1; user_map_if_not_mapped_noclear((addr_t)new + len + 1); env[i] = new; _strcpy(new, old); kfree(old); alen += len; } kfree(backup_env); } end = (env_start + alen) & PAGE_MASK; t->env = env; t->argv = argv; kfree(path); t->heap_start = t->heap_end = end + PAGE_SIZE; if(other_bitsize) raise_task_flag(t, TF_OTHERBS); user_map_if_not_mapped_noclear(t->heap_start); /* Zero the heap and stack */ memset((void *)end_l, 0, PAGE_SIZE-(end_l%PAGE_SIZE)); memset((void *)(end+PAGE_SIZE), 0, PAGE_SIZE); memset((void *)(STACK_LOCATION - STACK_SIZE), 0, STACK_SIZE); /* Release everything */ if(EXEC_LOG == 2) printk(0, "[%d]: Performing call\n", t->pid); set_int(0); lower_task_flag(t, TF_SCHED); if(!(kernel_state_flags & KSF_HAVEEXECED)) set_ksf(KSF_HAVEEXECED); arch_specific_exec_initializer(t, argc, eip); return 0; }