rlgwebd/sqlickrypt.c
John "Elwin" Edwards 6ed3b7c2ce sqlickrypt.c: finish switching to parametrized queries.
sqlickrypt should now be injection-resistant.
2012-06-03 18:26:11 -07:00

157 lines
3.9 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sqlite3.h>
#include <unistd.h>
#include <crypt.h>
#define DATABASE "/dgldir/dgamelaunch.db"
#define IBUFSIZE 200
int check(char *uname, char *pw) {
char *pwhash, *comphash;
char *query = "SELECT password FROM dglusers WHERE username=?;";
int status;
sqlite3 *db;
sqlite3_stmt *qstmt;
status = sqlite3_open(DATABASE, &db);
if (status) {
sqlite3_close(db);
return 3;
}
sqlite3_prepare_v2(db, query, -1, &qstmt, NULL);
if (qstmt == NULL) {
sqlite3_close(db);
return 3;
}
status = sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT);
if (status) {
sqlite3_finalize(qstmt);
sqlite3_close(db);
return 3;
}
status = sqlite3_step(qstmt);
if (status != SQLITE_ROW) {
sqlite3_finalize(qstmt);
sqlite3_close(db);
if (status == SQLITE_DONE)
return 2; /* User not found */
return 3;
}
pwhash = strdup((char *) sqlite3_column_text(qstmt, 0));
/* Clean up */
sqlite3_finalize(qstmt);
sqlite3_close(db);
/* Check the password */
comphash = crypt(pw, pwhash);
if (!strcmp(pwhash, comphash))
status = 0;
else
status = 1;
free(pwhash);
return status;
}
int insertuser(char *uname, char *pw, char *email) {
char *checkquery = "SELECT * FROM dglusers WHERE username = ?;";
char *addquery = "INSERT INTO dglusers (username, password, email) VALUES (?, ?, ?);";
int status;
sqlite3 *db;
sqlite3_stmt *qstmt;
status = sqlite3_open(DATABASE, &db);
if (status) {
sqlite3_close(db);
return 3;
}
/* Check for existing account in the same transaction with creating it. */
status = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
if (status) {
sqlite3_close(db);
return 3;
}
sqlite3_prepare_v2(db, checkquery, -1, &qstmt, NULL);
if (qstmt == NULL) {
sqlite3_close(db);
return 3;
}
sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT);
status = sqlite3_step(qstmt);
if (status != SQLITE_DONE) {
sqlite3_finalize(qstmt);
sqlite3_close(db);
if (status == SQLITE_ROW)
return 1; /* User already exists */
return 3;
}
/* The username doesn't exist yet, so create a new account. */
sqlite3_finalize(qstmt);
sqlite3_prepare_v2(db, addquery, -1, &qstmt, NULL);
if (qstmt == NULL) {
sqlite3_close(db);
return 3;
}
sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(qstmt, 2, strdup(crypt(pw, pw)), -1, free);
sqlite3_bind_text(qstmt, 3, email, -1, SQLITE_TRANSIENT);
status = sqlite3_step(qstmt);
if (status != SQLITE_DONE) {
sqlite3_finalize(qstmt);
sqlite3_close(db);
return 3;
}
status = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
sqlite3_finalize(qstmt);
sqlite3_close(db);
return status;
}
int main(int argc, char *argv[]) {
char ibuf[IBUFSIZE], *uname, *pw, *email;
char *cptr; // Utility pointer
int status;
/* Read in the username and password */
fgets(ibuf, IBUFSIZE, stdin);
uname = ibuf;
pw = strchr(uname, '\n');
if (pw == NULL)
exit(4); /* Truncated */
*pw = '\0';
pw++;
fgets(pw, IBUFSIZE - (pw - ibuf), stdin);
if (pw[strlen(pw) - 1] == '\n')
pw[strlen(pw) - 1] = '\0';
else
exit(4); /* Truncated */
if (argc > 1 && !strcmp(argv[1], "register")) {
email = pw + strlen(pw) + 1;
fgets(email, IBUFSIZE - (email - ibuf), stdin);
if (email[strlen(email) - 1] == '\n')
email[strlen(email) - 1] = '\0';
else
exit(4);
for (cptr = email; *cptr != '\0'; cptr++) {
if (!isalnum(*cptr) && !strchr("@._-", *cptr)) {
exit(4);
}
}
}
/* Sanitize the username, because it gets put into a query. */
for (cptr = uname; *cptr != '\0'; cptr++) {
if (!isalnum(*cptr)) {
exit(4);
}
}
if (argc == 1 || !strcmp(argv[1], "check"))
status = check(uname, pw);
else if (!strcmp(argv[1], "register")) {
status = insertuser(uname, pw, email);
}
else
status = 127;
return status;
}