]> begriffs open source - libpw/blob - pw.c
WIP: initial work
[libpw] / pw.c
1 #include "pw.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 #include <pwd.h>
7 #include <unistd.h>
8
9 bool
10 pw_set(sqlite3 *db, char *user, char *pass)
11 {
12         static const char *q =
13                 "INSERT INTO login (user, pass) VALUES (?1, ?2) "
14                 "ON CONFLICT (user) DO UPDATE SET pass = ?2";
15         static sqlite3_stmt *s;
16
17         if (!s && sqlite3_prepare_v2(db, q, -1, &s, NULL) != SQLITE_OK)
18                 return false;
19         if (sqlite3_bind_text(s, 1, user, -1, SQLITE_TRANSIENT) != SQLITE_OK)
20                 return false;
21
22         char hash[_PASSWORD_LEN];
23         // note that alternatives to bcrypt are emerging
24         // https://isopenbsdsecu.re/mitigations/password_hashing/
25         if (crypt_newhash(pass, "bcrypt,a", hash, sizeof hash) != 0)
26         {
27                 // TODO: free s
28                 return false;
29         }
30
31         if (sqlite3_bind_text(s, 2, hash, sizeof hash, SQLITE_TRANSIENT) != SQLITE_OK)
32                 return false;
33         if (sqlite3_step(s) != SQLITE_DONE)
34         {
35                 fprintf(stderr, "Can't set pw: %s\n", sqlite3_errmsg(db));
36                 return false;
37         }
38         
39         bool good = sqlite3_changes(db) > 0;
40         sqlite3_reset(s);
41
42         return good;
43 }
44
45 bool
46 pw_check(sqlite3 *db, char *user, char *pass)
47 {
48         static const char *q =
49                 "SELECT pass FROM login WHERE user = ?";
50         static sqlite3_stmt *s;
51
52         if (!s && sqlite3_prepare_v2(db, q, -1, &s, NULL) != SQLITE_OK)
53                 return false;
54         if (sqlite3_bind_text(s, 1, user, -1, SQLITE_TRANSIENT) != SQLITE_OK)
55         {
56                 fprintf(stderr, "Can't bind: %s\n", sqlite3_errmsg(db));
57                 return false;
58         }
59
60         if (sqlite3_step(s) != SQLITE_ROW)
61                 return false;
62         const unsigned char *dbhash = sqlite3_column_text(s, 0);
63
64         bool good = 0 == crypt_checkpass(pass, dbhash);
65         sqlite3_reset(s);
66         return good;
67 }
68
69 int main(int argc, char **argv){
70         sqlite3 *db = NULL;
71         int rc, fk_enabled;
72
73         if (argc !=2)
74         {
75                 fprintf(stderr, "Usage: %s DATABASE\n", argv[0]);
76                 goto fail;
77         }
78         rc = sqlite3_open(argv[1], &db);
79         if( rc ){
80                 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
81                 goto fail;
82         }
83
84         rc = sqlite3_db_config(db,
85                 SQLITE_DBCONFIG_ENABLE_FKEY, 1, &fk_enabled
86         );
87         if (rc != SQLITE_OK || !fk_enabled)
88         {
89                 fputs("Could not enable foreign keys in sqlite\n", stderr);
90                 return EXIT_FAILURE;
91         }
92
93         char *u1  = "foo@example.com", *p1 = "password123",
94                  *u1c = "FOO@EXAMPLE.COM";
95         pw_set(db, u1, p1);
96         printf("Checking pass: %d\n", pw_check(db, u1, p1));
97         printf("Checking mixed case: %d\n", pw_check(db, u1c, p1));
98         printf("Checking wrong pass: %d\n", pw_check(db, u1, "wrong"));
99
100         sqlite3_close(db);
101         return 0;
102
103 fail:
104         sqlite3_close(db);
105         return EXIT_FAILURE;
106 }