Mercurial > hg > rlgwebd
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); |