From 5019c543808e1de9585282a2dbc951cf951e0132 Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Wed, 4 Jan 2023 01:55:15 +0300 Subject: [PATCH] init(cgi): add Common Gateway Interface with authentication only --- CMakeLists.txt | 4 ++ cgi/cgi.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 cgi/cgi.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 03d1da6..be55947 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,3 +28,7 @@ add_library(tanabata SHARED ${TANABATA_SRC}) # Tanabata CLI app add_executable(tfm ${TANABATA_SRC} ${CLI_SRC}) + +# Authentication CGI app +add_executable(tfm-cgi ${TANABATA_SRC} cgi/cgi.c) +target_link_libraries(tfm-cgi fcgi ssl crypto pthread) diff --git a/cgi/cgi.c b/cgi/cgi.c new file mode 100644 index 0000000..2bfdbc3 --- /dev/null +++ b/cgi/cgi.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include + +#define TOKEN_RENTALTIME 604800 +#define TOKEN_SIZE 64 + +static time_t SID; +static char TOKEN[TOKEN_SIZE]; +static int socket_auth; +static int socket_cgi; + +int validate(FCGX_Request *request) { + if (time(NULL) - SID > TOKEN_RENTALTIME) { + return 1; + } + char token[TOKEN_SIZE]; + FCGX_GetStr(token, TOKEN_SIZE, request->in); + if (memcmp(token, TOKEN, TOKEN_SIZE) == 0) { + return 0; + } + return 1; +} + +static void *auth() { + FCGX_Request request; + if (FCGX_InitRequest(&request, socket_auth, FCGI_FAIL_ACCEPT_ON_INTR) != 0) { + exit(1); + } + unsigned char password[SHA256_DIGEST_LENGTH]; + FILE *passfile = fopen("/etc/tfm/password", "rb"); + if (passfile == NULL || + fread(password, 1, SHA256_DIGEST_LENGTH, passfile) < SHA256_DIGEST_LENGTH) { + exit(1); + } + fclose(passfile); + int rc; + char buffer[33]; + for (;;) { + static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&accept_mutex); + rc = FCGX_Accept_r(&request); + pthread_mutex_unlock(&accept_mutex); + if (rc < 0) { + break; + } + memset(buffer, 0, 33); + FCGX_GetStr(buffer, 32, request.in); + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256((const unsigned char *) buffer, strlen(buffer), hash); + if (memcmp(hash, password, SHA256_DIGEST_LENGTH) == 0) { + time(&SID); + uint64_t subtoken = SID; + SHA256((const unsigned char *) &subtoken, 8, hash); + for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { + sprintf(TOKEN + (i * 2), "%02x", hash[i]); + } + FCGX_PutS("Content-type: application/json\r\n\r\n" + "{\"status\":true,\"token\":\"", request.out); + FCGX_PutS(TOKEN, request.out); + FCGX_PutS("\"}\n", request.out); + FCGX_Finish_r(&request); + continue; + } + FCGX_PutS("Content-type: application/json\r\n\r\n" + "{\"status\":false}\n", request.out); + FCGX_Finish_r(&request); + } + return NULL; +} + +static void *tfmcgi() { + FCGX_Request request; + if (FCGX_InitRequest(&request, socket_cgi, FCGI_FAIL_ACCEPT_ON_INTR) != 0) { + exit(1); + } + int rc; + for (;;) { + static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&accept_mutex); + rc = FCGX_Accept_r(&request); + pthread_mutex_unlock(&accept_mutex); + if (rc < 0) { + break; + } + if (validate(&request) != 0) { + FCGX_PutS("Content-type: application/json\r\n\r\n" + "{\"status\":false}\n", request.out); + FCGX_Finish_r(&request); + continue; + } + FCGX_PutS("Content-type: application/json\r\n\r\n" + "{\"status\":true}\n", request.out); + FCGX_Finish_r(&request); + } + return NULL; +} + +int main() { + pthread_t thread_auth, thread_cgi; + FCGX_Init(); + if ((socket_auth = FCGX_OpenSocket("/tmp/tfm-auth.sock", 0)) == -1 || + (socket_cgi = FCGX_OpenSocket("/tmp/tfm-cgi.sock", 0)) == -1) { + return 1; + } + pthread_create(&thread_auth, NULL, auth, NULL); + pthread_create(&thread_cgi, NULL, tfmcgi, NULL); + pthread_join(thread_auth, NULL); + pthread_join(thread_cgi, NULL); + return 0; +}