Fossil SCM

Fix to checkin [8c91be8b], which was intended to allow the user to log in with the email found in the contact info field of the user table. That checkin is fine as far as it goes, but it only works if the caller doesn't subsequently try to use the passed user name for anything else, since it isn't actually a user name. This checkin causes the low-level login checking function to re-point the user name pointer at the actual login name discovered while scanning for matching email addresses.

wyoung 2018-08-11 16:59 trunk
Commit 33522ff4e6f074983f3ec0418ffdfe8eb98c8098f0a315412c4be13e9412e2b5
3 files changed +2 -2 +22 -10 +4 -16
--- src/json_login.c
+++ src/json_login.c
@@ -124,21 +124,21 @@
124124
125125
#if 0
126126
{
127127
/* only for debugging the PD()-incorrect-result problem */
128128
cson_object * o = NULL;
129
- uid = login_search_uid( name, pw );
129
+ uid = login_search_uid( &name, pw );
130130
payload = cson_value_new_object();
131131
o = cson_value_get_object(payload);
132132
cson_object_set( o, "n", cson_value_new_string(name,strlen(name)));
133133
cson_object_set( o, "p", cson_value_new_string(pw,strlen(pw)));
134134
return payload;
135135
}
136136
#endif
137137
uid = anonSeed
138138
? login_is_valid_anonymous(name, pw, anonSeed)
139
- : login_search_uid(name, pw)
139
+ : login_search_uid(&name, pw)
140140
;
141141
if( !uid ){
142142
g.json.resultCode = preciseErrors
143143
? FSL_JSON_E_LOGIN_FAILED_NOTFOUND
144144
: FSL_JSON_E_LOGIN_FAILED;
145145
--- src/json_login.c
+++ src/json_login.c
@@ -124,21 +124,21 @@
124
125 #if 0
126 {
127 /* only for debugging the PD()-incorrect-result problem */
128 cson_object * o = NULL;
129 uid = login_search_uid( name, pw );
130 payload = cson_value_new_object();
131 o = cson_value_get_object(payload);
132 cson_object_set( o, "n", cson_value_new_string(name,strlen(name)));
133 cson_object_set( o, "p", cson_value_new_string(pw,strlen(pw)));
134 return payload;
135 }
136 #endif
137 uid = anonSeed
138 ? login_is_valid_anonymous(name, pw, anonSeed)
139 : login_search_uid(name, pw)
140 ;
141 if( !uid ){
142 g.json.resultCode = preciseErrors
143 ? FSL_JSON_E_LOGIN_FAILED_NOTFOUND
144 : FSL_JSON_E_LOGIN_FAILED;
145
--- src/json_login.c
+++ src/json_login.c
@@ -124,21 +124,21 @@
124
125 #if 0
126 {
127 /* only for debugging the PD()-incorrect-result problem */
128 cson_object * o = NULL;
129 uid = login_search_uid( &name, pw );
130 payload = cson_value_new_object();
131 o = cson_value_get_object(payload);
132 cson_object_set( o, "n", cson_value_new_string(name,strlen(name)));
133 cson_object_set( o, "p", cson_value_new_string(pw,strlen(pw)));
134 return payload;
135 }
136 #endif
137 uid = anonSeed
138 ? login_is_valid_anonymous(name, pw, anonSeed)
139 : login_search_uid(&name, pw)
140 ;
141 if( !uid ){
142 g.json.resultCode = preciseErrors
143 ? FSL_JSON_E_LOGIN_FAILED_NOTFOUND
144 : FSL_JSON_E_LOGIN_FAILED;
145
+22 -10
--- src/login.c
+++ src/login.c
@@ -206,41 +206,53 @@
206206
/*
207207
** Searches for the user ID matching the given name and password.
208208
** On success it returns a positive value. On error it returns 0.
209209
** On serious (DB-level) error it will probably exit.
210210
**
211
+** zUsername uses double indirection because we may re-point *zUsername
212
+** at a C string allocated with fossil_strdup() if you pass an email
213
+** address instead and we find that address in the user table's info
214
+** field, which is expected to contain a string of the form "Human Name
215
+** <[email protected]>". In that case, *zUsername will point to that
216
+** user's actual login name on return, causing a leak unless the caller
217
+** is diligent enough to check whether its pointer was re-pointed.
218
+**
211219
** zPassword may be either the plain-text form or the encrypted
212220
** form of the user's password.
213221
*/
214
-int login_search_uid(const char *zUsername, const char *zPasswd){
215
- char *zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0);
222
+int login_search_uid(const char **zUsername, const char *zPasswd){
223
+ char *zSha1Pw = sha1_shared_secret(zPasswd, *zUsername, 0);
216224
int uid = db_int(0,
217225
"SELECT uid FROM user"
218226
" WHERE login=%Q"
219227
" AND length(cap)>0 AND length(pw)>0"
220228
" AND login NOT IN ('anonymous','nobody','developer','reader')"
221229
" AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))"
222230
" AND (info NOT LIKE '%%expires 20%%'"
223231
" OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))",
224
- zUsername, zSha1Pw, zPasswd
232
+ *zUsername, zSha1Pw, zPasswd
225233
);
226234
227235
/* If we did not find a login on the first attempt, and the username
228
- ** looks like an email address, the perhaps the user entired their
236
+ ** looks like an email address, then perhaps the user entered their
229237
** email address instead of their login. Try again to match the user
230238
** against email addresses contained in the "info" field.
231239
*/
232
- if( uid==0 && strchr(zUsername,'@')!=0 ){
240
+ if( uid==0 && strchr(*zUsername,'@')!=0 ){
233241
Stmt q;
234242
db_prepare(&q,
235243
"SELECT login FROM user"
236244
" WHERE find_emailaddr(info)=%Q"
237245
" AND instr(login,'@')==0",
238
- zUsername
246
+ *zUsername
239247
);
240
- while( uid==0 && db_step(&q)==SQLITE_ROW ){
241
- uid = login_search_uid(db_column_text(&q,0),zPasswd);
248
+ while( db_step(&q)==SQLITE_ROW ){
249
+ const char *zLogin = db_column_text(&q,0);
250
+ if( (uid = login_search_uid(&zLogin, zPasswd) ) != 0 ){
251
+ *zUsername = fossil_strdup(zLogin);
252
+ break;
253
+ }
242254
}
243255
db_finalize(&q);
244256
}
245257
free(zSha1Pw);
246258
return uid;
@@ -650,11 +662,11 @@
650662
redirect_to_g();
651663
}
652664
if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
653665
/* Attempting to log in as a user other than anonymous.
654666
*/
655
- uid = login_search_uid(zUsername, zPasswd);
667
+ uid = login_search_uid(&zUsername, zPasswd);
656668
if( uid<=0 ){
657669
sleep(1);
658670
zErrMsg =
659671
@ <p><span class="loginError">
660672
@ You entered an unknown user or an incorrect password.
@@ -951,11 +963,11 @@
951963
zPasswd = &zDecode[i+1];
952964
953965
/* Attempting to log in as the user provided by HTTP
954966
** basic auth
955967
*/
956
- uid = login_search_uid(zUsername, zPasswd);
968
+ uid = login_search_uid(&zUsername, zPasswd);
957969
if( uid>0 ){
958970
record_login_attempt(zUsername, zIpAddr, 1);
959971
}else{
960972
record_login_attempt(zUsername, zIpAddr, 0);
961973
962974
--- src/login.c
+++ src/login.c
@@ -206,41 +206,53 @@
206 /*
207 ** Searches for the user ID matching the given name and password.
208 ** On success it returns a positive value. On error it returns 0.
209 ** On serious (DB-level) error it will probably exit.
210 **
 
 
 
 
 
 
 
 
211 ** zPassword may be either the plain-text form or the encrypted
212 ** form of the user's password.
213 */
214 int login_search_uid(const char *zUsername, const char *zPasswd){
215 char *zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0);
216 int uid = db_int(0,
217 "SELECT uid FROM user"
218 " WHERE login=%Q"
219 " AND length(cap)>0 AND length(pw)>0"
220 " AND login NOT IN ('anonymous','nobody','developer','reader')"
221 " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))"
222 " AND (info NOT LIKE '%%expires 20%%'"
223 " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))",
224 zUsername, zSha1Pw, zPasswd
225 );
226
227 /* If we did not find a login on the first attempt, and the username
228 ** looks like an email address, the perhaps the user entired their
229 ** email address instead of their login. Try again to match the user
230 ** against email addresses contained in the "info" field.
231 */
232 if( uid==0 && strchr(zUsername,'@')!=0 ){
233 Stmt q;
234 db_prepare(&q,
235 "SELECT login FROM user"
236 " WHERE find_emailaddr(info)=%Q"
237 " AND instr(login,'@')==0",
238 zUsername
239 );
240 while( uid==0 && db_step(&q)==SQLITE_ROW ){
241 uid = login_search_uid(db_column_text(&q,0),zPasswd);
 
 
 
 
242 }
243 db_finalize(&q);
244 }
245 free(zSha1Pw);
246 return uid;
@@ -650,11 +662,11 @@
650 redirect_to_g();
651 }
652 if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
653 /* Attempting to log in as a user other than anonymous.
654 */
655 uid = login_search_uid(zUsername, zPasswd);
656 if( uid<=0 ){
657 sleep(1);
658 zErrMsg =
659 @ <p><span class="loginError">
660 @ You entered an unknown user or an incorrect password.
@@ -951,11 +963,11 @@
951 zPasswd = &zDecode[i+1];
952
953 /* Attempting to log in as the user provided by HTTP
954 ** basic auth
955 */
956 uid = login_search_uid(zUsername, zPasswd);
957 if( uid>0 ){
958 record_login_attempt(zUsername, zIpAddr, 1);
959 }else{
960 record_login_attempt(zUsername, zIpAddr, 0);
961
962
--- src/login.c
+++ src/login.c
@@ -206,41 +206,53 @@
206 /*
207 ** Searches for the user ID matching the given name and password.
208 ** On success it returns a positive value. On error it returns 0.
209 ** On serious (DB-level) error it will probably exit.
210 **
211 ** zUsername uses double indirection because we may re-point *zUsername
212 ** at a C string allocated with fossil_strdup() if you pass an email
213 ** address instead and we find that address in the user table's info
214 ** field, which is expected to contain a string of the form "Human Name
215 ** <[email protected]>". In that case, *zUsername will point to that
216 ** user's actual login name on return, causing a leak unless the caller
217 ** is diligent enough to check whether its pointer was re-pointed.
218 **
219 ** zPassword may be either the plain-text form or the encrypted
220 ** form of the user's password.
221 */
222 int login_search_uid(const char **zUsername, const char *zPasswd){
223 char *zSha1Pw = sha1_shared_secret(zPasswd, *zUsername, 0);
224 int uid = db_int(0,
225 "SELECT uid FROM user"
226 " WHERE login=%Q"
227 " AND length(cap)>0 AND length(pw)>0"
228 " AND login NOT IN ('anonymous','nobody','developer','reader')"
229 " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))"
230 " AND (info NOT LIKE '%%expires 20%%'"
231 " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))",
232 *zUsername, zSha1Pw, zPasswd
233 );
234
235 /* If we did not find a login on the first attempt, and the username
236 ** looks like an email address, then perhaps the user entered their
237 ** email address instead of their login. Try again to match the user
238 ** against email addresses contained in the "info" field.
239 */
240 if( uid==0 && strchr(*zUsername,'@')!=0 ){
241 Stmt q;
242 db_prepare(&q,
243 "SELECT login FROM user"
244 " WHERE find_emailaddr(info)=%Q"
245 " AND instr(login,'@')==0",
246 *zUsername
247 );
248 while( db_step(&q)==SQLITE_ROW ){
249 const char *zLogin = db_column_text(&q,0);
250 if( (uid = login_search_uid(&zLogin, zPasswd) ) != 0 ){
251 *zUsername = fossil_strdup(zLogin);
252 break;
253 }
254 }
255 db_finalize(&q);
256 }
257 free(zSha1Pw);
258 return uid;
@@ -650,11 +662,11 @@
662 redirect_to_g();
663 }
664 if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
665 /* Attempting to log in as a user other than anonymous.
666 */
667 uid = login_search_uid(&zUsername, zPasswd);
668 if( uid<=0 ){
669 sleep(1);
670 zErrMsg =
671 @ <p><span class="loginError">
672 @ You entered an unknown user or an incorrect password.
@@ -951,11 +963,11 @@
963 zPasswd = &zDecode[i+1];
964
965 /* Attempting to log in as the user provided by HTTP
966 ** basic auth
967 */
968 uid = login_search_uid(&zUsername, zPasswd);
969 if( uid>0 ){
970 record_login_attempt(zUsername, zIpAddr, 1);
971 }else{
972 record_login_attempt(zUsername, zIpAddr, 0);
973
974
+4 -16
--- src/smtp.c
+++ src/smtp.c
@@ -1353,27 +1353,15 @@
13531353
}
13541354
13551355
/*
13561356
** Try to log in for zUser and zPass.
13571357
**
1358
-** If zUser/zPass does not work as written, then modify zUser by
1359
-** omitting everything after the "@" (if there is one) and trying
1360
-** again.
1358
+** zUser can either point to a Fossil user name or to an email address
1359
+** found in the user table's info field, in angle brackets.
13611360
*/
1362
-static int pop3_login(char *zUser, char *zPass){
1363
- int uid;
1364
- int i;
1365
- uid = login_search_uid(zUser, zPass);
1366
- if( uid ) return 1;
1367
- for(i=0; zUser[i] && zUser[i]!='@'; i++){}
1368
- if( zUser[i]=='@' ){
1369
- zUser[i] = 0;
1370
- uid = login_search_uid(zUser, zPass);
1371
- if( uid ) return 1;
1372
- zUser[i] = '@';
1373
- }
1374
- return 0;
1361
+static int pop3_login(const char *zUser, char *zPass){
1362
+ return login_search_uid(&zUser, zPass) != 0;
13751363
}
13761364
13771365
/*
13781366
** COMMAND: pop3d
13791367
**
13801368
--- src/smtp.c
+++ src/smtp.c
@@ -1353,27 +1353,15 @@
1353 }
1354
1355 /*
1356 ** Try to log in for zUser and zPass.
1357 **
1358 ** If zUser/zPass does not work as written, then modify zUser by
1359 ** omitting everything after the "@" (if there is one) and trying
1360 ** again.
1361 */
1362 static int pop3_login(char *zUser, char *zPass){
1363 int uid;
1364 int i;
1365 uid = login_search_uid(zUser, zPass);
1366 if( uid ) return 1;
1367 for(i=0; zUser[i] && zUser[i]!='@'; i++){}
1368 if( zUser[i]=='@' ){
1369 zUser[i] = 0;
1370 uid = login_search_uid(zUser, zPass);
1371 if( uid ) return 1;
1372 zUser[i] = '@';
1373 }
1374 return 0;
1375 }
1376
1377 /*
1378 ** COMMAND: pop3d
1379 **
1380
--- src/smtp.c
+++ src/smtp.c
@@ -1353,27 +1353,15 @@
1353 }
1354
1355 /*
1356 ** Try to log in for zUser and zPass.
1357 **
1358 ** zUser can either point to a Fossil user name or to an email address
1359 ** found in the user table's info field, in angle brackets.
 
1360 */
1361 static int pop3_login(const char *zUser, char *zPass){
1362 return login_search_uid(&zUser, zPass) != 0;
 
 
 
 
 
 
 
 
 
 
 
1363 }
1364
1365 /*
1366 ** COMMAND: pop3d
1367 **
1368

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button