Use MD5 hashing to store passwords
[blerg.git] / common / auth.c
1 /* Blerg is (C) 2011 The Dominion of Awesome, and is distributed under a
2  * BSD-style license.  Please see the COPYING file for details.
3  */
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include "config.h"
11 #include "auth.h"
12 #include "util.h"
13 #include "md5.h"
14
15 #define TOKEN_SIZE 16
16 #define MAX_PASSWORD_LENGTH 64
17
18 int auth_set_password(const char *username, const char *password) {
19         char filename[512];
20         unsigned char md5pass[MD5_DIGEST_SIZE];
21         struct MD5Context ctx;
22         int fd, n;
23
24         if (!valid_name(username) || !blerg_exists(username))
25                 return 0;
26
27         n = strlen(password);
28         if (n > MAX_PASSWORD_LENGTH)
29                 return 0;
30
31         MD5Init(&ctx);
32         MD5Update(&ctx, username, strlen(username));
33         MD5Update(&ctx, password, n);
34         MD5Final(md5pass, &ctx);
35
36         snprintf(filename, 512, "%s/%s/password", DATA_PATH, username);
37         fd = open(filename, O_WRONLY | O_CREAT, 0600);
38         write(fd, md5pass, MD5_DIGEST_SIZE);
39         close(fd);
40         
41         return 1;
42 }
43
44 int auth_get_password(const char *username, char *password) {
45         char filename[512];
46         int fd;
47         int len = 0;
48
49         if (!valid_name(username))
50                 return 0;
51
52         sprintf(filename, "%s/%s/password", DATA_PATH, username);
53         fd = open(filename, O_RDONLY);
54         if (fd == -1)
55                 return 0;
56         len = read(fd, password, MD5_DIGEST_SIZE);
57         close(fd);
58
59         password[len] = 0;
60
61         return 1;
62 }
63
64 int auth_check_password(const char *username, const char *password) {
65         char epw[MD5_DIGEST_SIZE + 1];
66         unsigned char givenpw[MD5_DIGEST_SIZE];
67         struct MD5Context ctx;
68
69         if (auth_get_password(username, epw) == 0)
70                 return 0;
71
72         MD5Init(&ctx);
73         MD5Update(&ctx, username, strlen(username));
74         MD5Update(&ctx, password, strlen(password));
75         MD5Final(givenpw, &ctx);
76
77         if (strncmp(givenpw, epw, MD5_DIGEST_SIZE) == 0)
78                 return 1;
79         else
80                 return 0;
81 }
82
83 void hexify(char *dst, char *src, int len) {
84         static char hex[] = "0123456789abcdef";
85         int i;
86
87         for (i = 0; i < len; i++) {
88                 dst[i * 2]     = hex[(src[i] & 0xF0) >> 4];
89                 dst[i * 2 + 1] = hex[src[i] & 0xF];
90         }
91 }
92
93 char *create_random_token() {
94         unsigned char buf[TOKEN_SIZE];
95         char *token;
96         int rand_fd;
97
98         rand_fd = open("/dev/urandom", O_RDONLY);
99         if (rand_fd == -1) {
100                 perror("Could not open /dev/urandom\n");
101                 return 0;
102         }
103         read(rand_fd, buf, TOKEN_SIZE);
104         close(rand_fd);
105
106         token = malloc(TOKEN_SIZE * 2 + 1);
107         hexify(token, buf, TOKEN_SIZE);
108         token[TOKEN_SIZE * 2] = 0;
109
110         return token;
111 }
112
113 char * auth_login(const char *username, const char *password) {
114         char filename[512];
115         int token_fd;
116
117         if (!auth_check_password(username, password))
118                 return NULL;
119
120         char *token = create_random_token();
121
122         sprintf(filename, "%s/%s/tokens", DATA_PATH, username);
123         if (access(filename, F_OK) != 0) {
124                 if (mkdir(filename, 0700) == -1) {
125                         perror("Could not create auth token dir");
126                         return NULL;
127                 }
128         }
129
130         sprintf(filename, "%s/%s/tokens/%s", DATA_PATH, username, token);
131         token_fd = open(filename, O_WRONLY | O_CREAT, 0600);
132         if (token_fd == -1) {
133                 perror("Could not open token");
134                 return NULL;
135         }
136         close(token_fd);
137
138         return token;
139 }
140
141 int auth_logout(const char *username, const char *token) {
142         char filename[512];
143
144         if (!valid_name(username))
145                 return 0;
146
147         sprintf(filename, "%s/%s/tokens", DATA_PATH, username);
148         if (access(filename, F_OK) != 0) {
149                 return 0;
150         }
151
152         sprintf(filename, "%s/%s/tokens/%s", DATA_PATH, username, token);
153         if (unlink(filename) == -1)
154                 return 0;
155
156         return 1;
157 }
158
159 int auth_check_token(const char *username, const char *given_token) {
160         char filename[512];
161
162         sprintf(filename, "%s/%s/tokens/%s", DATA_PATH, username, given_token);
163
164         return (access(filename, F_OK) == 0);
165 }