Browse code

fix password processing (workaround to issues with libscrypt: don't use scrypt_hash, check that the salt is small)

Dario Rodriguez authored on 26/06/2014 11:58:59
Showing 3 changed files
... ...
@@ -17,6 +17,7 @@
17 17
 #include <unistd.h>
18 18
 #include "gen_res.h"
19 19
 #include "socklib.h"
20
+#include "loglib.h"
20 21
 #include "webkernel.h"
21 22
 #include "kakumei.h"
22 23
 #include "kakumei_session.h"
... ...
@@ -47,22 +48,24 @@ main(int argc, char *argv[])
47 48
         }
48 49
         port=atoi(argv[1]);
49 50
         if((ka->ssel=sselect_init())==NULL) {
50
-                fprintf(stderr,"ERROR: insufficient memory\n");
51
+                log_write("INIT","ERROR: insufficient memory");
51 52
                 return(1);
52 53
         }
53 54
         if((ka->web=wk_init(port,ka->ssel,NULL,callback_http,NULL,NULL,ka))==NULL) {
54 55
                 sselect_free(ka->ssel),ka->ssel=NULL;
55
-                fprintf(stderr,"ERROR: couldn't init web server\n");
56
+                log_write("INIT","ERROR: couldn't init web server");
56 57
                 return(2);
57 58
         }
58 59
         sigint_flag=0;
59 60
         signal_init(SIGINT,sigint);
61
+        log_write("INIT","Server initialized, waiting connections...");
60 62
         while(!sigint_flag) {
61 63
                 sselect_wait(ka->ssel,timeout);
62 64
                 wk_service(ka->web);
63 65
         }
64 66
         wk_free(ka->web),ka->web=NULL;
65 67
         sselect_free(ka->ssel),ka->ssel=NULL;
68
+        log_write("FINI","SIGINT detected, exiting...");
66 69
         return(0);
67 70
 }
68 71
 
... ...
@@ -134,22 +137,33 @@ callback_http(wk *web, int connid, wk_uri *uri, void *userptr)
134 137
         char *ptr;
135 138
         if(ka==NULL)
136 139
                 return(wkact_finished);
137
-        printf("http: %s\n",uri->path);
140
+        /* log without passwords */
141
+        if(memcmp(uri->path,"/login?",7)==0)
142
+                log_write("HTTP","Request: /login?...");
143
+        else if(memcmp(uri->path,"/newuser?",9)==0)
144
+                log_write("HTTP","Request: /newuser?...");
145
+        else
146
+                log_write("HTTP","Request: %s",uri->path);
147
+        /* check for an in-memory file */
138 148
         strncpy(partialpath,uri->path,sizeof(partialpath)-1);
139 149
         partialpath[sizeof(partialpath)-1]='\0';
140 150
         if((ptr=strchr(partialpath,'?'))!=NULL)
141 151
                 *ptr='\0';
152
+#warning TODO check if the page is a "protected" one and, in that case, check for correct session id
142 153
         if((strcmp(uri->path,"/")==0 && (res=res_find(resindexdata,"index.html"))!=NULL) ||
143 154
           (partialpath[0]=='/' && (res=res_find(resindexdata,partialpath+1))!=NULL)) {
155
+                log_write("HTTP","Serving in-memory file %s",partialpath+1);
144 156
                 wk_serve_buffer_as_file(web,connid,res->data,res->len,mime_getdefault(res->name,"application/octet-stream"));
145 157
                 return(wkact_finished);
146 158
         }
159
+        /* check for actions */
147 160
         if(memcmp(uri->path,"/login?",7)==0) {
148 161
                 return(http_login(web,connid,uri,userptr));
149 162
         } else if(memcmp(uri->path,"/newuser?",9)==0) {
150 163
                 return(http_newuser(web,connid,uri,userptr));
151 164
         }
152
-        printf("URI not found: %s\n",uri->path);
165
+        /* not found */
166
+        log_write("HTTP","URI not found: %s",uri->path);
153 167
         wk_serve_error(web,connid,wkerr_notfound);
154 168
         return(wkact_finished);
155 169
 }
... ...
@@ -179,8 +193,10 @@ http_login(wk *web, int connid, wk_uri *uri, void *userptr)
179 193
         char reply[1024];
180 194
         char session[SESSIONSIZE];
181 195
         kakumei *ka=(kakumei *)userptr;
182
-        if(web==NULL || connid<0 || uri==NULL || ka==NULL)
196
+        if(web==NULL || connid<0 || uri==NULL || ka==NULL) {
197
+                log_write("EINT","%s:%i",__FILE__,__LINE__);
183 198
                 return(wkact_finished); /* internal error */
199
+        }
184 200
         if(wk_uri_copyvar(uri,"u",u,sizeof(u))==NULL)
185 201
                 u[0]='\0';
186 202
         if(wk_uri_copyvar(uri,"p",p,sizeof(p))==NULL)
... ...
@@ -192,6 +208,7 @@ http_login(wk *web, int connid, wk_uri *uri, void *userptr)
192 208
                 snprintf(reply,sizeof(reply),"/newuser.html?i=%s",p);
193 209
                 reply[sizeof(reply)-1]='\0';
194 210
                 wk_serve_buffer_as_file(web,connid,reply,strlen(reply),"text/plain");
211
+                log_write("LGIN","Reply: %s",reply);
195 212
                 return(wkact_finished);
196 213
         } else if(pass_check(ka,u,p)==0 &&
197 214
                   session_new(ka,u,session,sizeof(session))!=NULL) {
... ...
@@ -199,8 +216,10 @@ http_login(wk *web, int connid, wk_uri *uri, void *userptr)
199 216
                 snprintf(reply,sizeof(reply),"/posts.html?s=%s",session);
200 217
                 reply[sizeof(reply)-1]='\0';
201 218
                 wk_serve_buffer_as_file(web,connid,reply,strlen(reply),"text/plain");
219
+                log_write("LGIN","Reply: %s",reply);
202 220
                 return(wkact_finished);
203 221
         }
222
+        log_write("LGIN","Serving error");
204 223
         wk_serve_error(web,connid,wkerr_internal);
205 224
         return(wkact_finished);
206 225
 }
... ...
@@ -212,10 +231,12 @@ http_newuser(wk *web, int connid, wk_uri *uri, void *userptr)
212 231
         char reply[1024];
213 232
         char session[SESSIONSIZE];
214 233
         kakumei *ka=(kakumei *)userptr;
215
-        if(web==NULL || connid<0 || uri==NULL || ka==NULL)
234
+        if(web==NULL || connid<0 || uri==NULL || ka==NULL) {
235
+                log_write("EINT","%s:%i",__FILE__,__LINE__);
216 236
                 return(wkact_finished); /* internal error */
237
+        }
217 238
         /* get vars */
218
-        if(wk_uri_copyvar(uri,"i",u,sizeof(i))==NULL)
239
+        if(wk_uri_copyvar(uri,"i",i,sizeof(i))==NULL)
219 240
                 i[0]='\0';
220 241
         if(wk_uri_copyvar(uri,"u",u,sizeof(u))==NULL)
221 242
                 u[0]='\0';
... ...
@@ -225,12 +246,14 @@ http_newuser(wk *web, int connid, wk_uri *uri, void *userptr)
225 246
         if(kakumei_inviteexists(ka,i)!=0) {
226 247
                 /* retry login */
227 248
                 wk_serve_buffer_as_file(web,connid,"/",1,"text/plain");
249
+                log_write("NEWU","invalid invite %s, redirecting to login",i);
228 250
                 return(wkact_finished);
229 251
         }
230 252
         /* create user */
231 253
         if(pass_new(ka,u,p)!=0) {
232 254
                 /* error with username */
233 255
                 wk_serve_error(web,connid,wkerr_internal);
256
+                log_write("NEWU","invalid user, send error");
234 257
                 return(wkact_finished);
235 258
         }
236 259
         /* delete invitation */
... ...
@@ -239,12 +262,14 @@ http_newuser(wk *web, int connid, wk_uri *uri, void *userptr)
239 262
         if(session_new(ka,u,session,sizeof(session))==NULL) {
240 263
                 /* "autologin" didn't work, ask for login */
241 264
                 wk_serve_buffer_as_file(web,connid,"/",1,"text/plain");
265
+                log_write("NEWU","couldn't generate new session, redirecting to login");
242 266
                 return(wkact_finished);
243 267
         }
244 268
         /* valid login */
245 269
         snprintf(reply,sizeof(reply),"/posts.html?s=%s",session);
246 270
         reply[sizeof(reply)-1]='\0';
247 271
         wk_serve_buffer_as_file(web,connid,reply,strlen(reply),"text/plain");
272
+        log_write("NEWU","Reply: %s",reply);
248 273
         return(wkact_finished);
249 274
 }
250 275
 
... ...
@@ -14,27 +14,54 @@
14 14
 #include <sys/types.h>
15 15
 #include <sys/stat.h>
16 16
 #include <fcntl.h>
17
+#include "loglib.h"
17 18
 #include "kakumei.h"
18 19
 #include "libscrypt.h"
19 20
 
21
+#define VALUE_N 16384
22
+#define VALUE_r 8
23
+#define VALUE_p 1
24
+
25
+static int mcf_gen(const char *salt,const char *passwd, char *mcf, int mcfsize);
26
+static int mcf_check(char *mcf, const char *passwd);
27
+
20 28
 int
21 29
 pass_new(kakumei *ka, char *user, char *passwd)
22 30
 {
23 31
         int fd;
24 32
         char filename[1024];
25
-        char mcf[SCRYPT_MCF_LEN+1];
26 33
         int len;
27
-        if(kakumei_uservalid(ka,user)!=0)
34
+        int res;
35
+        static const char mysalt[]={"NFkFsNdzMQ9Jfer"};
36
+        char mcf[SCRYPT_MCF_LEN];
37
+        if(kakumei_uservalid(ka,user)!=0) {
38
+                log_write("PASS","Ilegal username %s",user);
39
+                return(-1);
40
+        }
41
+        memset(mcf,0,sizeof(mcf));
42
+        if((res=mcf_gen(mysalt,passwd,mcf,sizeof(mcf)))!=0) {
43
+                log_write("PASS","Couln't create simple hash for user %s",user);
28 44
                 return(-1);
45
+        }
46
+        if((res=mcf_check(mcf,passwd))!=0) {
47
+                log_write("EINT","%s:%i",__FILE__,__LINE__);
48
+                return(-1); /* internal error */
49
+        }
50
+        mkdir(DATADIR,0700);
51
+        mkdir(USERSDIR,0700);
52
+        snprintf(filename,sizeof(filename)-1,"%s/%s",USERSDIR,user);
53
+        filename[sizeof(filename)-1]='\0';
54
+        mkdir(filename,0700);
29 55
         snprintf(filename,sizeof(filename)-1,"%s/%s/passwd",USERSDIR,user);
30 56
         filename[sizeof(filename)-1]='\0';
31
-        memset(mcf,0,sizeof(mcf));
32
-        libscrypt_hash(mcf,passwd,SCRYPT_N,SCRYPT_r,SCRYPT_p);
33
-        if((fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0600))==-1)
57
+        if((fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0600))==-1) {
58
+                log_write("PASS","Couln't open for writing to %s",filename);
34 59
                 return(-1);
60
+        }
35 61
         len=strlen(mcf);
36 62
         if(write(fd,mcf,len)!=len) {
37 63
                 close(fd),fd=-1;
64
+                log_write("PASS","Error writing to %s",filename);
38 65
                 return(-1);
39 66
         }
40 67
         close(fd),fd=-1;
... ...
@@ -46,17 +73,67 @@ pass_check(kakumei *ka, char *user, char *passwd)
46 73
 {
47 74
         int fd;
48 75
         char filename[1024];
49
-        char mcf[SCRYPT_MCF_LEN+1];
50
-        if(kakumei_userexists(ka,user)!=0)
76
+        char mcf[SCRYPT_MCF_LEN];
77
+        int res;
78
+        if(kakumei_userexists(ka,user)!=0) {
79
+                log_write("PASS","No username %s",user);
51 80
                 return(-1);
81
+        }
52 82
         snprintf(filename,sizeof(filename)-1,"%s/%s/passwd",USERSDIR,user);
53 83
         filename[sizeof(filename)-1]='\0';
54
-        if((fd=open(filename,O_RDONLY))==-1)
84
+        if((fd=open(filename,O_RDONLY))==-1) {
85
+                log_write("PASS","Couldn't read passwd of user %s",user);
55 86
                 return(-1);
87
+        }
56 88
         memset(mcf,0,sizeof(mcf));
57 89
         read(fd,mcf,sizeof(mcf)-1);
58 90
         close(fd),fd=-1;
59
-        if(libscrypt_check(mcf,passwd)<=0)
91
+        if((res=mcf_check(mcf,passwd))!=0) {
92
+                log_write("PASS","Wrong password trying to login for user %s",user);
93
+                return(-1);
94
+        }
95
+        return(0);
96
+}
97
+
98
+/* utility functions to make libscrypt usable */
99
+static int
100
+mcf_gen(const char *salt,const char *passwd, char *mcf, int mcfsize)
101
+{
102
+        int res;
103
+        uint8_t hashbuf[SCRYPT_HASH_LEN];
104
+        char saltbuf[1024];
105
+        char outbuf[1024];
106
+        if(mcfsize<SCRYPT_MCF_LEN)
107
+                return(-1);
108
+        if(strlen(salt)>16)
109
+                return(-1); /* large salts make libscrypt break */
110
+        if((res=libscrypt_scrypt((uint8_t*)passwd,strlen(passwd),
111
+          (uint8_t*)salt, strlen(salt), VALUE_N,VALUE_r,VALUE_p, hashbuf, sizeof(hashbuf)))!=0) {
112
+                log_write("PASS","Couln't create hash");
113
+                return(-1);
114
+        }
115
+        if((res=libscrypt_b64_encode(outbuf, (char*)hashbuf, sizeof(hashbuf)))==-1) {
116
+                log_write("PASS","Couln't encode hash");
117
+                return(-1);
118
+        }
119
+        if((res=libscrypt_b64_encode(saltbuf, salt, strlen(salt)))==-1) {
120
+                log_write("PASS","Couln't encode salt");
121
+                return(-1);
122
+        }
123
+        if(!(res=libscrypt_mcf(VALUE_N,VALUE_r,VALUE_p, saltbuf, outbuf, mcf))) {
124
+                log_write("PASS","Couln't convert to mcf");
125
+                return(-1);
126
+        }
127
+        return(0);
128
+}
129
+
130
+static int
131
+mcf_check(char *mcf, const char *passwd)
132
+{
133
+        char mcftest[SCRYPT_MCF_LEN];
134
+        int res;
135
+        memcpy(mcftest,mcf,sizeof(mcftest));
136
+        if((res=libscrypt_check(mcftest,(char *)passwd))<=0)
60 137
                 return(-1);
61 138
         return(0);
62 139
 }
... ...
@@ -51,10 +51,10 @@ session_new(kakumei *ka, char *user, char *session, int sessionsize)
51 51
         mhash_deinit(td,&binhash);
52 52
         for(i=0;i<sizeof(binhash);i++) {
53 53
                 c=(((unsigned char *)binhash)[i]>>4);
54
-                c=(c>=10)?(c-10+'a'):c;
54
+                c=(c>=10)?(c-10+'a'):c+'0';
55 55
                 session[i<<1]=c;
56 56
                 c=(((unsigned char *)binhash)[i]&0xf);
57
-                c=(c>=10)?(c-10+'a'):c;
57
+                c=(c>=10)?(c-10+'a'):c+'0';
58 58
                 session[(i<<1)+1]=c;
59 59
         }
60 60
         session[sizeof(binhash)]='\0';
... ...
@@ -72,6 +72,8 @@ session_new(kakumei *ka, char *user, char *session, int sessionsize)
72 72
         }
73 73
         close(fd),fd=-1;
74 74
         /* delete the previous session of the user */
75
+        mkdir(DATADIR,0700);
76
+        mkdir(USERSDIR,0700);
75 77
         snprintf(filename,sizeof(filename)-1,"%s/%s/session",USERSDIR,user);
76 78
         filename[sizeof(filename)-1]='\0';
77 79
         if((fd=open(filename,O_RDONLY))!=-1) {