comparison sqlickrypt.c @ 143:f1676e81c80a

sqlickrypt: add support for salted SHA-512 passwords, and fix NULL bug. Passwords will now be securely encrypted with random salt. Also avoid storing NULL in the database, because that makes dgamelaunch segfault.
author John "Elwin" Edwards
date Sun, 20 Oct 2013 21:19:13 -0700
parents 0a3ff1267c24
children bc69717ff386
comparison
equal deleted inserted replaced
142:c4304f08e35b 143:f1676e81c80a
6 #include <unistd.h> 6 #include <unistd.h>
7 #include <crypt.h> 7 #include <crypt.h>
8 8
9 #define DATABASE "/dgldir/dgamelaunch.db" 9 #define DATABASE "/dgldir/dgamelaunch.db"
10 #define IBUFSIZE 200 10 #define IBUFSIZE 200
11 #define RANDOMSRC "/dev/urandom"
11 12
12 /* General idea for return status: 13 /* General idea for return status:
13 * 0: success 14 * 0: success
14 * 1: password check failed 15 * 1: password check failed
15 * 2: username not found 16 * 2: username not found
38 sqlite3_finalize(stmt); 39 sqlite3_finalize(stmt);
39 sqlite3_close(db); 40 sqlite3_close(db);
40 if (status) 41 if (status)
41 exit(status); 42 exit(status);
42 return; 43 return;
44 }
45
46 char encode64(unsigned char c) {
47 if (c < 26)
48 return 'a' + c;
49 else if (c < 52)
50 return 'A' + c - 26;
51 else if (c < 62)
52 return '0' + c - 52;
53 else if (c == 62)
54 return '.';
55 else
56 return '/';
57 }
58
59 /* Initializes a SHA-512 salt. salt must contain at least 20 bytes. */
60 void setsalt(char *salt) {
61 unsigned char rnbytes[3], rnvals[4];
62 FILE *urandom;
63 int loop;
64 salt[0] = salt[2] = salt[19] = '$'; /* Delimiters */
65 salt[1] = '6'; /* SHA-512 */
66 urandom = fopen(RANDOMSRC, "r");
67 for (loop = 0; loop < 4; loop++) {
68 fread(rnbytes, 1, 3, urandom);
69 rnvals[0] = rnbytes[0] >> 2;
70 rnvals[1] = ((rnbytes[0] & 0x03) << 4) | ((rnbytes[1] & 0xf0) >> 4);
71 rnvals[2] = ((rnbytes[1] & 0x0f) << 2) | ((rnbytes[2] & 0xc0) >> 6);
72 rnvals[3] = rnbytes[2] & 0x3f;
73 salt[loop * 4 + 3] = encode64(rnvals[0]);
74 salt[loop * 4 + 4] = encode64(rnvals[1]);
75 salt[loop * 4 + 5] = encode64(rnvals[2]);
76 salt[loop * 4 + 6] = encode64(rnvals[3]);
77 }
78 fclose(urandom);
43 } 79 }
44 80
45 int check(char *uname, char *pw) { 81 int check(char *uname, char *pw) {
46 char *pwhash, *comphash; 82 char *pwhash, *comphash;
47 char *query = "SELECT password FROM dglusers WHERE username=?;"; 83 char *query = "SELECT password FROM dglusers WHERE username=?;";
74 return status; 110 return status;
75 } 111 }
76 112
77 int insertuser(char *uname, char *pw, char *email) { 113 int insertuser(char *uname, char *pw, char *email) {
78 char *checkquery = "SELECT * FROM dglusers WHERE username = ?;"; 114 char *checkquery = "SELECT * FROM dglusers WHERE username = ?;";
79 char *addquery = "INSERT INTO dglusers (username, password, email) VALUES (?, ?, ?);"; 115 char *addquery = "INSERT INTO dglusers (username, password, email, flags, env) VALUES (?, ?, ?, ?, ?);";
80 int status; 116 int status;
81 sqlite3 *db; 117 sqlite3 *db;
82 sqlite3_stmt *qstmt; 118 sqlite3_stmt *qstmt;
119 char salt[20];
83 120
84 opendb(&db, &qstmt, checkquery); 121 opendb(&db, &qstmt, checkquery);
85 /* Check for existing account in the same transaction with creating it. */ 122 /* Check for existing account in the same transaction with creating it. */
86 status = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); 123 status = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
87 if (status) 124 if (status)
94 if (status == SQLITE_ROW) 131 if (status == SQLITE_ROW)
95 return 1; /* User already exists */ 132 return 1; /* User already exists */
96 return 3; 133 return 3;
97 } 134 }
98 /* The username doesn't exist yet, so create a new account. */ 135 /* The username doesn't exist yet, so create a new account. */
136 setsalt(salt);
99 sqlite3_finalize(qstmt); 137 sqlite3_finalize(qstmt);
100 sqlite3_prepare_v2(db, addquery, -1, &qstmt, NULL); 138 sqlite3_prepare_v2(db, addquery, -1, &qstmt, NULL);
101 if (qstmt == NULL) 139 if (qstmt == NULL)
102 cleanup(db, NULL, 3); 140 cleanup(db, NULL, 3);
103 sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT); 141 sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT);
104 sqlite3_bind_text(qstmt, 2, strdup(crypt(pw, pw)), -1, free); 142 sqlite3_bind_text(qstmt, 2, strdup(crypt(pw, salt)), -1, free);
105 sqlite3_bind_text(qstmt, 3, email, -1, SQLITE_TRANSIENT); 143 sqlite3_bind_text(qstmt, 3, email, -1, SQLITE_TRANSIENT);
144 sqlite3_bind_int(qstmt, 4, 0);
145 sqlite3_bind_text(qstmt, 5, "", -1, SQLITE_STATIC);
106 status = sqlite3_step(qstmt); 146 status = sqlite3_step(qstmt);
107 if (status != SQLITE_DONE) 147 if (status != SQLITE_DONE)
108 cleanup(db, qstmt, 3); 148 cleanup(db, qstmt, 3);
109 status = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); 149 status = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
110 cleanup(db, qstmt, 0); 150 cleanup(db, qstmt, 0);
158 char *setquery = "UPDATE dglusers SET password = ? WHERE username = ?;"; 198 char *setquery = "UPDATE dglusers SET password = ? WHERE username = ?;";
159 sqlite3 *db; 199 sqlite3 *db;
160 sqlite3_stmt *qstmt; 200 sqlite3_stmt *qstmt;
161 int status; 201 int status;
162 char *hash; 202 char *hash;
163 203 char salt[20];
164 /* This is not a smart use of crypt, but it needs to be compatible with 204
165 * dgamelaunch. */ 205 setsalt(salt);
166 hash = crypt(newpw, newpw); 206 hash = crypt(newpw, salt);
167 opendb(&db, &qstmt, setquery); 207 opendb(&db, &qstmt, setquery);
168 status = sqlite3_bind_text(qstmt, 2, uname, -1, SQLITE_TRANSIENT); 208 status = sqlite3_bind_text(qstmt, 2, uname, -1, SQLITE_TRANSIENT);
169 if (status) 209 if (status)
170 cleanup(db, qstmt, 3); 210 cleanup(db, qstmt, 3);
171 status = sqlite3_bind_text(qstmt, 1, hash, -1, SQLITE_TRANSIENT); 211 status = sqlite3_bind_text(qstmt, 1, hash, -1, SQLITE_TRANSIENT);