diff options
author | lamp | 2023-03-05 21:48:37 +0000 |
---|---|---|
committer | lamp | 2023-03-05 21:48:37 +0000 |
commit | 998b06d89b869b9587830ec767c6e30f851fff29 (patch) | |
tree | 08b4a4478dc224abec092611fed40b79769cb216 /passcached.c |
initmain
Diffstat (limited to 'passcached.c')
-rw-r--r-- | passcached.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/passcached.c b/passcached.c new file mode 100644 index 0000000..4ac7ba4 --- /dev/null +++ b/passcached.c @@ -0,0 +1,175 @@ +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> + +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include "common.h" + +#define BACKLOG 5 + +struct CacheEntry { + struct CacheEntry* next; + char* entry_name; + char* secret; +}; + +struct CacheEntry cache; + +volatile sig_atomic_t done = 0; + +void term(int signum) { + done = 1; +} + +char* pass_secret_for_actual(char* entry_name, int* exit_code) { + int link[2]; + pid_t pid; + if (pipe(link) == -1) { + die("pipe() failed!"); + } + if ((pid = fork()) == -1) { + die("fork() failed!"); + } + if (pid == 0) { + dup2 (link[1], STDOUT_FILENO); + close(link[0]); + close(link[1]); + execlp("pass", "pass", entry_name, NULL); + die("execlp() failed!"); + } else { + if (close(link[1]) == -1) { + fprintf(stderr, "%s\n", "close() failed!"); + } + char* final = malloc(BUF_SIZE); + if (!final) { + die("malloc() failed!"); + } + char* buf = malloc(BUF_SIZE); + int nbytes = 0; + while(0 != (nbytes = read(link[0], buf, sizeof(buf)))) { + buf[nbytes] = 0; + if (strlen(final) + strlen(buf) < BUF_SIZE) { + strcat(final, buf); + } + } + if (waitpid(pid, exit_code, 0) == -1) { + fprintf(stderr, "%s\n", "waitpid() failed!"); + return NULL; + } else { + return final; + } + } + // TODO + *exit_code = 0; + return "test"; +} + +char* pass_secret_for(char* entry_name, int* exit_code) { + struct CacheEntry* current = &cache; + while (current->next) { + if (!strcmp(entry_name, current->next->entry_name)) { + // cache hit + *exit_code = 0; + return current->next->secret; + } + current = current->next; + } + // cache miss + char* secret = pass_secret_for_actual(entry_name, exit_code); + if (secret && WIFEXITED(*exit_code) && (WEXITSTATUS(*exit_code) == 0)) { + struct CacheEntry* new_entry = malloc(sizeof(struct CacheEntry)); + if (!new_entry) { + die("malloc() failed!"); + } + new_entry->next = NULL; + char* new_entry_name = malloc(strlen(entry_name) + 1); + if (!new_entry_name) { + die("malloc() failed!"); + } + strcpy(new_entry_name, entry_name); + new_entry->entry_name = new_entry_name; + new_entry->secret = secret; + current->next = new_entry; + return new_entry->secret; + } else { + return secret; + } +} + +void destroy_cache(void) { + struct CacheEntry* current = cache.next; + while (current) { + struct CacheEntry* next = current->next; + free(current->entry_name); + free(current->secret); + free(current); + current = next; + } +} + +int main(int argc, char *argv[]) { + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + action.sa_handler = term; + sigaction(SIGTERM, &action, NULL); + struct sockaddr_un addr; + + int sfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sfd == -1) { + die("socket() failed!"); + } + + char* spath = get_socket_path(); + if (strlen(spath) > sizeof(addr.sun_path) - 1) { + die("Server socket path too long!"); + } + + if (remove(spath) == -1 && errno != ENOENT) { + die("remove() failed!"); + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, spath, sizeof(addr.sun_path) - 1); + + if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) { + die("bind() failed!"); + } + + if (listen(sfd, BACKLOG) == -1) { + die("listen() failed!"); + } + + printf("Listening at: %s\n", spath); + + cache.next = NULL; + cache.entry_name = NULL; + cache.secret = NULL; + char buf[BUF_SIZE]; + while (!done) { + int cfd = accept(sfd, NULL, NULL); + printf("Accepted socket fd = %d\n", cfd); + if (read(cfd, buf, BUF_SIZE) > 0) { + int exit_code = 0; + char* secret = pass_secret_for(buf, &exit_code); + if (!secret || !(WIFEXITED(exit_code) && WEXITSTATUS(exit_code) == 0)) { + secret = ""; + } + if (write(cfd, secret, strlen(secret) + 1) != strlen(secret) + 1) { + fprintf(stderr, "%s\n", "write() failed!"); + } + } + + if (close(cfd) == -1) { + fprintf(stderr, "%s\n", "close() failed!"); + } + } + close(sfd); + destroy_cache(); + free_socket_path(spath); +} |