Task: SQL-based authentication

C: #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>

#include <mysql.h>
#include <openssl/md5.h>

void end_with_db(void);

MYSQL *mysql = NULL; 

bool connect_db(const char *host, const char *user, const char *pwd,
		const char *db, unsigned int port)
{
  if ( mysql == NULL )
  {
    if (mysql_library_init(0, NULL, NULL)) return false;
    mysql = mysql_init(NULL); if ( mysql == NULL ) return false;
    MYSQL *myp = mysql_real_connect(mysql, host, user, pwd, db, port, NULL, 0);
    if (myp == NULL) {
      fprintf(stderr, "connection error: %s\n", mysql_error(mysql));
      end_with_db();
      return false;
    }
  }
  return true; 
}

#define USERNAMELIMIT 32

#define PASSWORDLIMIT 32
#define SALTBYTE 16
bool create_user(const char *username, const char *password)
{
  int i;
  char binarysalt[SALTBYTE];
  char salt[SALTBYTE*2+1];
  char md5hash[MD5_DIGEST_LENGTH];
  char saltpass[SALTBYTE+PASSWORDLIMIT+1];
  char pass_md5[MD5_DIGEST_LENGTH*2 + 1];
  char user[USERNAMELIMIT*2 + 1];
  char *q = NULL;
  static const char query[] = 
    "INSERT INTO users "
    "(username,pass_salt,pass_md5) "
    "VALUES ('%s', X'%s', X'%s')";
  static const size_t qlen = sizeof query;
  

  for(i=0; username[i] != '\0' && i < USERNAMELIMIT; i++) ;
  if ( username[i] != '\0' ) return false;
  for(i=0; password[i] != '\0' && i < PASSWORDLIMIT; i++) ;
  if ( password[i] != '\0' ) return false;

  srand(time(NULL));

  for(i=0; i < SALTBYTE; i++)
  {
    
    binarysalt[i] = rand()%256; 
  }

  (void)mysql_hex_string(salt, binarysalt, SALTBYTE);
  
  for(i=0; i < SALTBYTE; i++) saltpass[i] = binarysalt[i];
  strcpy(saltpass+SALTBYTE, password);
  (void)MD5(saltpass, SALTBYTE + strlen(password), md5hash);
  (void)mysql_hex_string(pass_md5, md5hash, MD5_DIGEST_LENGTH);

  (void)mysql_real_escape_string(mysql, user, username, strlen(username));

  
  q = malloc(qlen + USERNAMELIMIT*2 + MD5_DIGEST_LENGTH*2 + SALTBYTE*2 + 1);
  if ( q == NULL ) return false;
  sprintf(q, query, user, salt, pass_md5);
#if defined(DEBUG)
  fprintf(stderr, "QUERY:\n%s\n\n", q);
#endif
  int res = mysql_query(mysql, q);
  free(q);
  if ( res != 0 )
  {
    fprintf(stderr, "create_user query error: %s\n", mysql_error(mysql));
    return false;
  }
  return true;
}


bool authenticate_user(const char *username, const char *password)
{
  char user[USERNAMELIMIT*2 + 1];
  char md5hash[MD5_DIGEST_LENGTH];
  char saltpass[SALTBYTE+PASSWORDLIMIT+1];
  bool authok = false;
  char *q = NULL;
  int i;
  static const char query[] = 
    "SELECT * FROM users WHERE username='%s'";
  static const size_t qlen = sizeof query;

  
  for(i=0; username[i] != '\0' && i < USERNAMELIMIT; i++) ;
  if ( username[i] != '\0' ) return false;
  for(i=0; password[i] != '\0' && i < PASSWORDLIMIT; i++) ;
  if ( password[i] != '\0' ) return false;

  (void)mysql_real_escape_string(mysql, user, username, strlen(username));  

  q = malloc(qlen + strlen(user) + 1);
  if (q == NULL) return false;
  sprintf(q, query, username);

  int res = mysql_query(mysql, q);
  free(q);
  if ( res != 0 )
  {
    fprintf(stderr, "authenticate_user query error: %s\n", mysql_error(mysql));
    return false;
  }

  MYSQL_RES *qr = mysql_store_result(mysql);
  if ( qr == NULL ) return false;

  
  if ( mysql_num_rows(qr) != 1 ) {
    mysql_free_result(qr);
    return false;
  }

  MYSQL_ROW row = mysql_fetch_row(qr);          
  unsigned long *len = mysql_fetch_lengths(qr); 

  memcpy(saltpass, row[2], len[2]); 
  memcpy(saltpass + len[2], password, strlen(password));
  (void)MD5(saltpass, SALTBYTE + strlen(password), md5hash);

  authok = memcmp(md5hash, row[3], len[3]) == 0;
  mysql_free_result(qr);

  return authok;
}

void end_with_db(void)
{
  mysql_close(mysql); mysql = NULL;
  mysql_library_end();
}

int main(int argc, char **argv)
{

  if ( argc < 4 ) return EXIT_FAILURE;

  if ( connect_db("localhost", "devel", "", "test", 0 ) )
  {
    if ( strcmp(argv[1], "add") == 0 )
    {
      if (create_user(argv[2], argv[3])) 
	printf("created\n");
    } else if ( strcmp(argv[1], "auth") == 0 ) {
      if (authenticate_user(argv[2], argv[3]))
	printf("authorized\n");
      else
	printf("access denied\n");
    } else {
      printf("unknown command\n");
    }
    end_with_db();
  }
  return EXIT_SUCCESS;
}







Python: import mysql.connector 
import hashlib
 
import sys	 
import random	 
 
DB_HOST = "localhost"	 
DB_USER = "devel" 
DB_PASS = "devel"	 
DB_NAME = "test"	 
 
def connect_db():	 
    	 
    try:	 
        return mysql.connector.connect(host=DB_HOST, user=DB_USER, passwd=DB_PASS, db=DB_NAME)	 
    except:	 
        return False	 
 
def create_user(username, passwd):	 
    	 
    db = connect_db()	 
    if not db:	 
        print "Can't connect MySQL!"
        return None
 
    cursor = db.cursor()	 
 
    salt = randomValue(16)	 	 
    passwd_md5 = hashlib.md5(salt+passwd).hexdigest()	 
 
    
    try:	 
        cursor.execute("INSERT INTO users (`username`, `pass_salt`, `pass_md5`) VALUES (%s, %s, %s)", (username, salt, passwd_md5)) 
        cursor.execute("SELECT userid FROM users WHERE username=%s", (username,) ) 
        id = cursor.fetchone()
        db.commit()
        cursor.close()
        db.close()
        return id[0]	 
    except:	 
        print 'Username was already taken. Please select another'	 
        return None
 
def authenticate_user(username, passwd):	 
    db = connect_db()	 
    if not db:	 
        print "Can't connect MySQL!"
        return False
 
    cursor = db.cursor()	 
 
    cursor.execute("SELECT pass_salt, pass_md5 FROM users WHERE username=%s", (username,))

    row = cursor.fetchone()
    cursor.close()
    db.close()
    if row is None:     
        return False
    salt = row[0]
    correct_md5 = row[1]
    tried_md5 = hashlib.md5(salt+passwd).hexdigest()
    return correct_md5 == tried_md5
 
def randomValue(length):	 
    	 
    salt_chars = 'abcdefghijklmnopqrstuvwxyz0123456789'

    return ''.join(random.choice(salt_chars) for x in range(length))
 
if __name__ == '__main__':	 
    user = randomValue(10)
    passwd = randomValue(16)	 
 
    new_user_id = create_user(user, passwd)
    if new_user_id is None:
        print 'Failed to create user %s' % user
        sys.exit(1)
    auth = authenticate_user(user, passwd)	 
    if auth:	 
        print 'User %s authenticated successfully' % user	 
    else:	 
        print 'User %s failed' % user