bambi6-service-postit

Simple Note-Taking A/D Service for BambiCTF6 in 2021
git clone https://git.sinitax.com/sinitax/bambi6-service-postit
Log | Files | Refs | README | LICENSE | sfeed.txt

postit.c (10275B)


      1#include <stdlib.h>
      2#include <stdint.h>
      3#include <stdio.h>
      4#include <string.h>
      5#include <unistd.h>
      6#include <signal.h>
      7#include <time.h>
      8
      9#include "sqlite3.h"
     10
     11#include "util.h"
     12#include "crypto.h"
     13
     14static char *current_user = NULL;
     15static sqlite3 *db = NULL;
     16
     17static const char *BANNER =
     18"\n"
     19"...........................................................\n"
     20": ########::: #######::: ######:: ########: ####: ########:\n"
     21": ##.... ##: ##.... ##: ##... ##:... ##..::. ##::... ##..::\n"
     22": ##:::: ##: ##:::: ##: ##:::..::::: ##::::: ##::::: ##::::\n"
     23": ########:: ##:::: ##:. ######::::: ##::::: ##::::: ##::::\n"
     24": ##.....::: ##:::: ##::..... ##:::: ##::::: ##::::: ##::::\n"
     25": ##:::::::: ##:::: ##: ##::: ##:::: ##::::: ##::::: ##::::\n"
     26": ##::::::::. #######::. ######::::: ##:::: ####:::: ##::::\n"
     27":..::::::::::.......::::......::::::..:::::....:::::..:::::\n"
     28"\n"
     29" Commands: help, register, users, info, login, post, posts\n"
     30"\n";
     31
     32void
     33cleanup(void)
     34{
     35	sqlite3_close(db);
     36}
     37
     38void
     39timeout(int sig)
     40{
     41	printf("time's up!\n");
     42	exit(1);
     43}
     44
     45void
     46init(int argc, const char **argv)
     47{
     48	const char *dbpath, *sql;
     49	char *err_msg = NULL;
     50	int status;
     51
     52	setvbuf(stdin, NULL, _IONBF, 0);
     53	setvbuf(stdout, NULL, _IONBF, 0);
     54
     55	dbpath = "db.sqlite3";
     56	if (argc > 1) dbpath = argv[1];
     57
     58	status = sqlite3_open(dbpath, &db);
     59	ASSERTV(status == SQLITE_OK, "Cannot access database: %s",
     60		sqlite3_errmsg(db));
     61
     62	status = sqlite3_busy_timeout(db, 10000);
     63	ASSERTV(status == SQLITE_OK, "Failed to set busy timeout: %s",
     64		sqlite3_errmsg);
     65
     66	sql = "CREATE TABLE IF NOT EXISTS users(uid INTEGER PRIMARY KEY,"
     67		" name TEXT, mod TEXT, exp TEXT, creat INTEGER);";
     68	status = sqlite3_exec(db, sql, 0, 0, NULL);
     69	ASSERTV(status == SQLITE_OK, "Failed to create users table: %s",
     70		sqlite3_errmsg(db));
     71
     72	sql = "CREATE TABLE IF NOT EXISTS posts(pid INTEGER PRIMARY KEY,"
     73		" uid INTEGER SECONDARY KEY, text TEXT,"
     74		" creat INTEGER);";
     75	status = sqlite3_exec(db, sql, 0, 0, NULL);
     76	ASSERTV(status == SQLITE_OK, "Failed to create posts table: %s",
     77		sqlite3_errmsg(db));
     78
     79	signal(SIGALRM, timeout);
     80
     81	atexit(cleanup);
     82}
     83
     84int
     85user_id(const char *username)
     86{
     87	sqlite3_stmt *res;
     88	int status, uid;
     89
     90	status = sqlite3_prepare_v2(db, "SELECT uid FROM users WHERE name = ?",
     91		-1, &res, NULL);
     92	ASSERTV(status == SQLITE_OK, "Failed to fetch users from database: %s",
     93		sqlite3_errmsg(db));
     94
     95	status = sqlite3_bind_text(res, 1, username, -1, NULL);
     96	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
     97		sqlite3_errmsg(db));
     98
     99	uid = -1;
    100	if (sqlite3_step(res) == SQLITE_ROW)
    101		uid = sqlite3_column_int(res, 0);
    102
    103	sqlite3_finalize(res);
    104
    105	return uid;
    106}
    107
    108void
    109user_info(const char *username, char **exp, char **mod)
    110{
    111	sqlite3_stmt *res;
    112	int status, uid;
    113
    114	status = sqlite3_prepare_v2(db, "SELECT exp, mod FROM users WHERE name = ?",
    115		-1, &res, NULL);
    116	ASSERTV(status == SQLITE_OK, "Failed to fetch users from database: %s",
    117		sqlite3_errmsg(db));
    118
    119	status = sqlite3_bind_text(res, 1, username, -1, NULL);
    120	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    121		sqlite3_errmsg(db));
    122
    123	ASSERT(sqlite3_step(res) == SQLITE_ROW);
    124
    125	*exp = strdup((void*) sqlite3_column_text(res, 0));
    126	ASSERT(*exp != NULL);
    127
    128	*mod = strdup((void*) sqlite3_column_text(res, 1));
    129	ASSERT(*mod != NULL);
    130
    131	sqlite3_finalize(res);
    132}
    133
    134void
    135api_create_user(char *username)
    136{
    137	sqlite3_stmt *res;
    138	char *mod, *exp;
    139	int status;
    140
    141	if (!username) {
    142		printf("Please supply a username\n");
    143		return;
    144	}
    145
    146	if (user_id(username) >= 0) {
    147		printf("A user with that name already exists\n");
    148		return;
    149	}
    150
    151	mod = NULL;
    152	exp = strdup(ask("Enter RSA exponent: "));
    153	ASSERT(exp != NULL);
    154	if (!is_numstr(exp)) {
    155		printf("Invalid RSA exponent\n");
    156		goto cleanup;
    157	}
    158
    159	mod = strdup(ask("Enter RSA modulus: "));
    160	ASSERT(mod != NULL);
    161	if (!is_numstr(mod)) {
    162		printf("Invalid RSA modulus\n");
    163		goto cleanup;
    164	}
    165
    166	status = sqlite3_prepare_v2(db,
    167		"INSERT INTO users (name, exp, mod, creat) VALUES (?, ?, ?, ?);",
    168		-1, &res, NULL);
    169	ASSERTV(status == SQLITE_OK, "Failed to fetch data from database: %s",
    170		sqlite3_errmsg(db));
    171
    172	status = sqlite3_bind_text(res, 1, username, -1, NULL);
    173	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    174		sqlite3_errmsg(db));
    175
    176	status = sqlite3_bind_text(res, 2, exp, -1, NULL);
    177	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    178		sqlite3_errmsg(db));
    179
    180	status = sqlite3_bind_text(res, 3, mod, -1, NULL);
    181	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    182		sqlite3_errmsg(db));
    183
    184	status = sqlite3_bind_int(res, 4, time(NULL));
    185	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    186		sqlite3_errmsg(db));
    187
    188	ASSERTV(sqlite3_step(res) == SQLITE_DONE, "Failed to create user: %s",
    189		sqlite3_errmsg(db));
    190
    191	sqlite3_finalize(res);
    192
    193cleanup:
    194	free(exp);
    195	free(mod);
    196}
    197
    198void
    199api_list_users(char *args)
    200{
    201	sqlite3_stmt *res;
    202	int status;
    203
    204	status = sqlite3_prepare_v2(db, "SELECT name FROM users", -1, &res, NULL);
    205	ASSERTV(status == SQLITE_OK, "Failed to fetch data from database: %s",
    206		sqlite3_errmsg(db));
    207
    208	while (sqlite3_step(res) == SQLITE_ROW)
    209		printf("- %s\n", sqlite3_column_text(res, 0));
    210
    211	sqlite3_finalize(res);
    212}
    213
    214void
    215api_user_info(char *username)
    216{
    217	sqlite3_stmt *res;
    218	int status, uid;
    219
    220	if (!username) {
    221		printf("Please supply a username\n");
    222		return;
    223	}
    224
    225	if ((uid = user_id(username)) < 0) {
    226		printf("A user with that name does not exist\n");
    227		return;
    228	}
    229
    230	status = sqlite3_prepare_v2(db, "SELECT name, exp, mod FROM users WHERE uid = ?",
    231		-1, &res, NULL);
    232	ASSERTV(status == SQLITE_OK, "Failed to fetch data from database: %s",
    233		sqlite3_errmsg(db));
    234
    235	status = sqlite3_bind_int(res, 1, uid);
    236	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    237		sqlite3_errmsg(db));
    238
    239	ASSERTV(sqlite3_step(res) == SQLITE_ROW, "Failed to fetch user data: %s",
    240		sqlite3_errmsg(db));
    241
    242	printf("Username: %s\n", sqlite3_column_text(res, 0));
    243	printf("RSA Exponent: %s\n", sqlite3_column_text(res, 1));
    244	printf("RSA Modulus: %s\n", sqlite3_column_text(res, 2));
    245
    246	sqlite3_finalize(res);
    247}
    248
    249void
    250api_login(char *username)
    251{
    252	const char *sig;
    253	char *chall, *exp, *mod;
    254	int uid;
    255
    256	if (!username) {
    257		printf("Please supply a username\n");
    258		return;
    259	}
    260
    261	if ((uid = user_id(username)) < 0) {
    262		printf("A user with that name does not exist\n");
    263		return;
    264	}
    265
    266	exp = mod = NULL;
    267	chall = randstr(16);
    268	printf("Please verify your identity.\n");
    269	printf("Sign this message: %s\n", chall);
    270
    271	sig = ask("Signature: ");
    272	if (!is_numstr(sig)) {
    273		printf("Invalid signature format (base 10)\n");
    274		goto cleanup;
    275	}
    276
    277	user_info(username, &exp, &mod);
    278
    279	if (!check_signature(chall, sig, exp, mod)) {
    280		printf("Invalid signature\n");
    281		goto cleanup;
    282	}
    283
    284	if (current_user) free(current_user);
    285	current_user = strdup(username);
    286	ASSERT(current_user != NULL);
    287
    288cleanup:
    289	free(chall);
    290	free(mod);
    291	free(exp);
    292}
    293
    294void
    295api_create_post(char *msg)
    296{
    297	sqlite3_stmt *res;
    298	int uid, status;
    299
    300	if (!current_user) {
    301		printf("Not logged in!\n");
    302		return;
    303	}
    304
    305	ASSERT((uid = user_id(current_user)) >= 0);
    306
    307	if (!msg || !*msg) {
    308		printf("Message can not be empty\n");
    309		return;
    310	}
    311
    312	status = sqlite3_prepare_v2(db,
    313		"INSERT INTO posts (uid, text, creat) VALUES (?, ?, ?);",
    314		-1, &res, NULL);
    315	ASSERTV(status == SQLITE_OK, "Failed to fetch data from database: %s",
    316		sqlite3_errmsg(db));
    317
    318	status = sqlite3_bind_int(res, 1, uid);
    319	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    320		sqlite3_errmsg(db));
    321
    322	status = sqlite3_bind_text(res, 2, msg, -1, NULL);
    323	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    324		sqlite3_errmsg(db));
    325
    326	status = sqlite3_bind_int(res, 3, time(NULL));
    327	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    328		sqlite3_errmsg(db));
    329
    330	ASSERTV(sqlite3_step(res) == SQLITE_DONE, "Failed to create post: %s",
    331		sqlite3_errmsg(db));
    332
    333	sqlite3_finalize(res);
    334}
    335
    336void
    337api_list_posts(char *args)
    338{
    339	sqlite3_stmt *res;
    340	const char post_text;
    341	int uid, status;
    342
    343	if (!current_user) {
    344		printf("Not logged in!\n");
    345		return;
    346	}
    347
    348	ASSERT((uid = user_id(current_user)) >= 0);
    349
    350	status = sqlite3_prepare_v2(db, "SELECT text FROM posts WHERE uid = ?",
    351		-1, &res, NULL);
    352	ASSERTV(status == SQLITE_OK, "Failed to fetch posts from database: %s",
    353		sqlite3_errmsg(db));
    354
    355	status = sqlite3_bind_int(res, 1, uid);
    356	ASSERTV(status == SQLITE_OK, "Failed to bind param to sql query: %s",
    357		sqlite3_errmsg(db));
    358
    359	while (sqlite3_step(res) == SQLITE_ROW)
    360		printf("- %s\n", sqlite3_column_text(res, 0));
    361
    362	sqlite3_finalize(res);
    363}
    364
    365void
    366api_help(char *command)
    367{
    368	struct {
    369		const char *cmd, *args, *desc;
    370	} descs[] = {
    371		{ "help", "COMMAND", "Returns usage information" },
    372		{ "register", "USER", "Create a new user" },
    373		{ "login", "USER", "Login as a user" },
    374		{ "users", "", "Lists all registered users" },
    375		{ "post", "", "Create a new post as the current user" },
    376		{ "posts", "", "Lists posts created by the current user" },
    377	};
    378	int i;
    379
    380	if (!command) {
    381		printf("Supply a command to view usage info\n");
    382		return;
    383	}
    384
    385	for (i = 0; i < ARRSIZE(descs); i++) {
    386		if (!strcmp(descs[i].cmd, command)) {
    387			printf("%s %s%s: %s\n", descs[i].cmd, descs[i].args,
    388				*descs[i].args ? " " : "", descs[i].desc);
    389			break;
    390		}
    391	}
    392
    393	if (i == ARRSIZE(descs))
    394		printf("Unknown command: %s\n", command);
    395}
    396
    397int
    398main(int argc, const char **argv)
    399{
    400	struct {
    401		const char *name;
    402		void (*func)(char *args);
    403	} cmds[] = {
    404		{ "register", api_create_user },
    405		{ "users", api_list_users },
    406		{ "info", api_user_info },
    407		{ "login", api_login },
    408		{ "post", api_create_post },
    409		{ "posts", api_list_posts },
    410		{ "help", api_help },
    411	};
    412	char *cmd, *tok, *args;
    413	int exit, i;
    414
    415	init(argc, argv);
    416
    417	printf("%s", BANNER);
    418
    419	exit = 0;
    420	while (!exit) {
    421		alarm(120);
    422		cmd = ask("\r$ ");
    423		if (!*cmd) continue;
    424
    425		cmd = strdup(cmd);
    426		ASSERT(cmd != NULL);
    427
    428		tok = strchr(cmd, ' ');
    429		if (tok) *tok = '\0';
    430		args = tok ? tok + 1 : NULL;
    431		if (args && !*args) args = NULL;
    432
    433		for (i = 0; i < ARRSIZE(cmds); i++) {
    434			if (!strcmp(cmd, cmds[i].name)) {
    435				cmds[i].func(args);
    436				break;
    437			}
    438		}
    439
    440		if (!strcmp(cmd, "exit"))
    441			break;
    442
    443		if (i == ARRSIZE(cmds))
    444			printf("Unknown command: %s\n", cmd);
    445
    446		free(cmd);
    447	}
    448
    449	printf("bye!\n");
    450	sqlite3_close(db);
    451}