diff --git a/README.md b/README.md index a8dd55b..313670a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,24 @@ # libparzel-shadow -A parser for the /etc/shadow - file on Linux systems \ No newline at end of file +A simple parser for reading the `/etc/shadow`-file on a linux-system. +The API should be self-explanatory for anyone in the know of the concept +of iterators. + +## Building + +Run `bash build.bash ` where profile can be one of `small`, +`release` or `debug`. Alternatively, the script can just be started for getting +a prompt of what should be done. + +After that, the binary files can be removed using `bash build.bash cleanup`. + +## Test Executable + +The test executable writes out the names of all users in the file at `/etc/shadow` +to STDOUT. It needs superuser permission. + +## TO-DO + +Currently, only the user can be read out by the parser. More isn't needed +at the moment. Once more is needed, it will be done. + diff --git a/build.bash b/build.bash new file mode 100644 index 0000000..67b2ebc --- /dev/null +++ b/build.bash @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +set -e +mkdir -p build/ + +build_debug() { + gcc -g -c -o build/shadow_parser.o src/shadow_parser.c -I inc/ + + ar -rvs build/libparzel-shadow.a \ + build/shadow_parser.o + mv build/libparzel-shadow.a . + + gcc -g -o write_shadow_names.elf main.c libparzel-shadow.a -I inc/ +} + +build_fast() { + gcc -O3 -c -o build/shadow_parser.o src/shadow_parser.c -I inc/ + + ar -rvs build/libparzel-shadow.a \ + build/shadow_parser.o + mv build/libparzel-shadow.a . + + gcc -O3 -o write_shadow_names.elf main.c libparzel-shadow.a -I inc/ +} + +build_small() { + gcc -Os -c -o build/shadow_parser.o src/shadow_parser.c -I inc/ + + ar -rvs build/libparzel-shadow.a \ + build/shadow_parser.o + mv build/libparzel-shadow.a . + + gcc -Os -o write_shadow_names.elf main.c libparzel-shadow.a -I inc/ +} + +BUILD_PROFILE=$1 +REMAINING_TRIES=3 + +while [[ $REMAINING_TRIES > 0 ]] do + case $BUILD_PROFILE in + "debug") + build_debug + exit + ;; + "release" | "fast") + build_fast + exit + ;; + "small") + build_small + exit + ;; + "cleanup") + rm write_shadow_names.elf + rm libparzel-shadow.a + rm -r build/ + exit + ;; + *) + printf "Profile (debug | release | small): " + read BUILD_PROFILE + ;; + esac + let REMAINING_TRIES-- +done + +echo "Tries exhausted" diff --git a/inc/libparzel_shadow.h b/inc/libparzel_shadow.h new file mode 100644 index 0000000..818a418 --- /dev/null +++ b/inc/libparzel_shadow.h @@ -0,0 +1,35 @@ + +#ifndef LIBPARZEL_SHADOW_H +#define LIBPARZEL_SHADOW_H + +#include +#include + +typedef struct shadow_user +{ + char *name; + +} shadow_user_s; + +typedef struct shadow_iterator +{ + uint32_t num_users; + shadow_user_s *users; + + int32_t index; + +} shadow_iterator_s; + +shadow_iterator_s shadow_parse (char *source, uint32_t len_source); +shadow_iterator_s shadow_new_iterator (char *path); +void shadow_cleanup (shadow_iterator_s iterator); + +bool shadow_next_user (shadow_iterator_s *iterator, shadow_user_s *user); +void shadow_rewind (shadow_iterator_s *iterator); +void shadow_seek (shadow_iterator_s *iterator, int32_t distance); + +uint32_t shadow_length (shadow_iterator_s *iterator); +uint32_t shadow_remaining (shadow_iterator_s *iterator); + +#endif // SHADOW_PARSER_H + diff --git a/main.c b/main.c new file mode 100644 index 0000000..c047baf --- /dev/null +++ b/main.c @@ -0,0 +1,16 @@ +#include + +#include + +int main(int argc, char **argv) +{ + shadow_iterator_s iterator = shadow_new_iterator("/etc/shadow"); + + shadow_user_s user; + while(shadow_next_user(&iterator, &user)) + { + printf("User's Name: %s\n", user.name); + } + shadow_cleanup(iterator); +} + diff --git a/src/shadow_parser.c b/src/shadow_parser.c new file mode 100644 index 0000000..2149ec9 --- /dev/null +++ b/src/shadow_parser.c @@ -0,0 +1,141 @@ +#include + +#include +#include +#include +#include + +shadow_iterator_s shadow_parse(char *source, uint32_t len_source) +{ + uint32_t users_capacity = 32; + + shadow_iterator_s iterator; + iterator.users = malloc(sizeof(shadow_user_s) * users_capacity); + iterator.num_users = 0; + iterator.index = 0; + + uint32_t index = 0; + while(index < len_source) + { + if(iterator.num_users >= users_capacity) + { + users_capacity *= 2; + iterator.users = realloc(iterator.users, sizeof(shadow_user_s) * users_capacity); + } + uint32_t name_start = index; + + // Extract username + while(index < len_source) + { + if(source[index] == ':') break; + ++index; + } + uint32_t len_name = index - name_start; + + shadow_user_s user; + user.name = malloc(len_name+1); + memcpy(user.name, &source[name_start], len_name); + user.name[len_name] = 0; + + iterator.users[iterator.num_users] = user; + ++iterator.num_users; + + // Skip to newline + while(index < len_source) + { + if(source[index] == '\n') break; + ++index; + } + ++index; + } + free(source); + + return iterator; +} + +shadow_iterator_s shadow_new_iterator(char *path) +{ + FILE *file = fopen(path, "r"); + + if(file == NULL) + { + printf("Error in %s at line %u!\n", __FILE__, __LINE__); + printf("Failed opening file: %s\n", path); + shadow_iterator_s invalid_iterator; + invalid_iterator.index = -1; + invalid_iterator.num_users = 0; + invalid_iterator.users = NULL; + return invalid_iterator; + } + + fseek(file, 0, SEEK_END); + uint32_t len_file = ftell(file); + fseek(file, 0, SEEK_SET); + + char *source = malloc(len_file+1); + if(fread(source, len_file, 1, file) == 0) + { + puts("Read wrong amount of bytes!"); + } + source[len_file] = 0x00; + + fclose(file); + + return shadow_parse(source, len_file); +} + +void shadow_cleanup(shadow_iterator_s iterator) +{ + uint32_t index = 0; + while(index < iterator.num_users) + { + free(iterator.users[index].name); + ++index; + } + free(iterator.users); +} + + + +bool shadow_next_user(shadow_iterator_s *iterator, shadow_user_s *user) +{ + if(iterator->index >= iterator->num_users) + { + return false; + } + (*user) = iterator->users[iterator->index]; + ++iterator->index; + + return true; +} + +void shadow_rewind(shadow_iterator_s *iterator) +{ + iterator->index = 0; +} + +void shadow_seek(shadow_iterator_s *iterator, int32_t distance) +{ + iterator->index += distance; + if(iterator->index > iterator->num_users) + { + iterator->index = iterator->num_users; + } + if(iterator->index < 0) + { + iterator->index = 0; + } +} + + + +uint32_t shadow_length(shadow_iterator_s *iterator) +{ + return iterator->num_users; +} + +uint32_t shadow_remaining(shadow_iterator_s *iterator) +{ + return iterator->num_users - iterator->index; +} +