view sqlickrypt.c @ 24:9d5da43c0e83

sqlickrypt.c: begin converting to parametrized queries. Switch the check() function to use parametrized SQL queries instead of contructing statements with strcat(), for obvious reasons.
author John "Elwin" Edwards <elwin@sdf.org>
date Sun, 03 Jun 2012 17:08:40 -0700
parents 59ea628abb81
children f275d816e857
line wrap: on
line source

#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 xcallback(void *targ, int ncols, char **vals, char **colnames) {
  char *pws;
  int j;
  pws = *((char **) targ);
  if (pws == NULL) {
    for (j = 0; j < ncols; j++) {
      if (!strcmp(colnames[j], "password"))
        *((char **) targ) = strdup(vals[j]);
    }
  }
  /* Otherwise, this isn't the first row. */
  return 0;
}

/* Simple callback, for checking if there are any matches. */
int searchcallback(void *targ, int ncols, char **vals, char **colnames) {
  *((int *) targ) = 1;
  return 0;
}

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 finduser_sql[160];
  int status;
  sqlite3 *db;

  strcpy(finduser_sql, "BEGIN; SELECT * FROM dglusers WHERE username='");
  strncat(finduser_sql, uname, 40);
  strcat(finduser_sql, "';");

  status = sqlite3_open(DATABASE, &db);
  if (status) {
    sqlite3_close(db);
    return 1;
  }
  status = 0;
  sqlite3_exec(db, finduser_sql, searchcallback, (void *) &status, NULL);
  if (!status) {
    /* FIXME This is ugly, and email is unsanitzed. */
    strcpy(finduser_sql, "INSERT INTO dglusers (username, password, email) VALUES ('");
    strncat(finduser_sql, uname, 20);
    strcat(finduser_sql, "', '");
    strcat(finduser_sql, crypt(pw, pw));
    strcat(finduser_sql, "', '");
    strncat(finduser_sql, email, 40);
    strcat(finduser_sql, "');");
    sqlite3_exec(db, finduser_sql, NULL, NULL, NULL);
  }
  sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
  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;
}