Fossil SCM
Fix a bug in single sign-on. Add comments to the login source code.
Commit
9df4dcb5e1f3ff64a058c1bd3c41e6325a07a8ca
Parent
e9754eaeffa5446…
1 file changed
+41
-16
+41
-16
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -17,16 +17,20 @@ | ||
| 17 | 17 | ** |
| 18 | 18 | ** This file contains code for generating the login and logout screens. |
| 19 | 19 | ** |
| 20 | 20 | ** Notes: |
| 21 | 21 | ** |
| 22 | -** There are two special-case user-ids: "anonymous" and "nobody". | |
| 22 | +** There are four special-case user-ids: "anonymous", "nobody", | |
| 23 | +** "developer" and "reader". | |
| 24 | +** | |
| 23 | 25 | ** The capabilities of the nobody user are available to anyone, |
| 24 | 26 | ** regardless of whether or not they are logged in. The capabilities |
| 25 | 27 | ** of anonymous are only available after logging in, but the login |
| 26 | 28 | ** screen displays the password for the anonymous login, so this |
| 27 | -** should not prevent a human user from doing so. | |
| 29 | +** should not prevent a human user from doing so. The capabilities | |
| 30 | +** of developer and reader are inherited by any user that has the | |
| 31 | +** "v" and "u" capabilities, respectively. | |
| 28 | 32 | ** |
| 29 | 33 | ** The nobody user has capabilities that you want spiders to have. |
| 30 | 34 | ** The anonymous user has capabilities that you want people without |
| 31 | 35 | ** logins to have. |
| 32 | 36 | ** |
| @@ -78,11 +82,11 @@ | ||
| 78 | 82 | /* |
| 79 | 83 | ** Return the name of the login cookie. |
| 80 | 84 | ** |
| 81 | 85 | ** The login cookie name is always of the form: fossil-XXXXXXXXXXXXXXXX |
| 82 | 86 | ** where the Xs are the first 16 characters of the login-group-code or |
| 83 | -** the project-code if we are not a member of any login-group. | |
| 87 | +** of the project-code if we are not a member of any login-group. | |
| 84 | 88 | */ |
| 85 | 89 | static char *login_cookie_name(void){ |
| 86 | 90 | static char *zCookieName = 0; |
| 87 | 91 | if( zCookieName==0 ){ |
| 88 | 92 | zCookieName = db_text(0, |
| @@ -107,15 +111,14 @@ | ||
| 107 | 111 | fossil_redirect_home(); |
| 108 | 112 | } |
| 109 | 113 | } |
| 110 | 114 | |
| 111 | 115 | /* |
| 112 | -** The IP address of the client is stored as part of the anonymous | |
| 113 | -** login cookie for additional security. But some clients are behind | |
| 114 | -** firewalls that shift the IP address with each HTTP request. To | |
| 115 | -** allow such (broken) clients to log in, extract just a prefix of the | |
| 116 | -** IP address. | |
| 116 | +** The IP address of the client is stored as part of login cookies. | |
| 117 | +** But some clients are behind firewalls that shift the IP address | |
| 118 | +** with each HTTP request. To allow such (broken) clients to log in, | |
| 119 | +** extract just a prefix of the IP address. | |
| 117 | 120 | */ |
| 118 | 121 | static char *ipPrefix(const char *zIP){ |
| 119 | 122 | int i, j; |
| 120 | 123 | for(i=j=0; zIP[i]; i++){ |
| 121 | 124 | if( zIP[i]=='.' ){ |
| @@ -125,11 +128,12 @@ | ||
| 125 | 128 | } |
| 126 | 129 | return mprintf("%.*s", i, zIP); |
| 127 | 130 | } |
| 128 | 131 | |
| 129 | 132 | /* |
| 130 | -** Return an abbreviated project code. | |
| 133 | +** Return an abbreviated project code. The abbreviation is the first | |
| 134 | +** 16 characters of the project code. | |
| 131 | 135 | ** |
| 132 | 136 | ** Memory is obtained from malloc. |
| 133 | 137 | */ |
| 134 | 138 | static char *abbreviated_project_code(const char *zFullCode){ |
| 135 | 139 | return mprintf("%.16s", zFullCode); |
| @@ -217,15 +221,17 @@ | ||
| 217 | 221 | login_check_credentials(); |
| 218 | 222 | zUsername = P("u"); |
| 219 | 223 | zPasswd = P("p"); |
| 220 | 224 | anonFlag = P("anon")!=0; |
| 221 | 225 | if( P("out")!=0 ){ |
| 226 | + /* To logout, change the cookie value to an empty string */ | |
| 222 | 227 | const char *zCookieName = login_cookie_name(); |
| 223 | 228 | cgi_set_cookie(zCookieName, "", login_cookie_path(), -86400); |
| 224 | 229 | redirect_to_g(); |
| 225 | 230 | } |
| 226 | 231 | if( g.okPassword && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ |
| 232 | + /* The user requests a password change */ | |
| 227 | 233 | zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); |
| 228 | 234 | if( db_int(1, "SELECT 0 FROM user" |
| 229 | 235 | " WHERE uid=%d AND (pw=%Q OR pw=%Q)", |
| 230 | 236 | g.userUid, zPasswd, zSha1Pw) ){ |
| 231 | 237 | sleep(1); |
| @@ -264,14 +270,22 @@ | ||
| 264 | 270 | redirect_to_g(); |
| 265 | 271 | return; |
| 266 | 272 | } |
| 267 | 273 | } |
| 268 | 274 | } |
| 269 | - zIpAddr = PD("REMOTE_ADDR","nil"); | |
| 270 | - zRemoteAddr = ipPrefix(zIpAddr); | |
| 275 | + zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */ | |
| 276 | + zRemoteAddr = ipPrefix(zIpAddr); /* Abbreviated IP address */ | |
| 271 | 277 | uid = isValidAnonymousLogin(zUsername, zPasswd); |
| 272 | 278 | if( uid>0 ){ |
| 279 | + /* Successful login as anonymous. Set a cookie that looks like | |
| 280 | + ** this: | |
| 281 | + ** | |
| 282 | + ** HASH/TIME/anonymous | |
| 283 | + ** | |
| 284 | + ** Where HASH is the sha1sum of TIME/IPADDR/SECRET, in which IPADDR | |
| 285 | + ** is the abbreviated IP address and SECRET is captcha-secret. | |
| 286 | + */ | |
| 273 | 287 | char *zNow; /* Current time (julian day number) */ |
| 274 | 288 | char *zCookie; /* The login cookie */ |
| 275 | 289 | const char *zCookieName; /* Name of the login cookie */ |
| 276 | 290 | Blob b; /* Blob used during cookie construction */ |
| 277 | 291 | |
| @@ -286,10 +300,12 @@ | ||
| 286 | 300 | cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), 6*3600); |
| 287 | 301 | record_login_attempt("anonymous", zIpAddr, 1); |
| 288 | 302 | redirect_to_g(); |
| 289 | 303 | } |
| 290 | 304 | if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ |
| 305 | + /* Attempting to log in as a user other than anonymous. | |
| 306 | + */ | |
| 291 | 307 | zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0); |
| 292 | 308 | uid = db_int(0, |
| 293 | 309 | "SELECT uid FROM user" |
| 294 | 310 | " WHERE login=%Q" |
| 295 | 311 | " AND length(cap)>0 AND length(pw)>0" |
| @@ -304,10 +320,17 @@ | ||
| 304 | 320 | @ You entered an unknown user or an incorrect password. |
| 305 | 321 | @ </span></p> |
| 306 | 322 | ; |
| 307 | 323 | record_login_attempt(zUsername, zIpAddr, 0); |
| 308 | 324 | }else{ |
| 325 | + /* Non-anonymous login is successful. Set a cookie of the form: | |
| 326 | + ** | |
| 327 | + ** HASH/PROJECT/LOGIN | |
| 328 | + ** | |
| 329 | + ** where HASH is a random hex number, PROJECT is either project | |
| 330 | + ** code prefix, and LOGIN is the user name. | |
| 331 | + */ | |
| 309 | 332 | char *zCookie; |
| 310 | 333 | const char *zCookieName = login_cookie_name(); |
| 311 | 334 | const char *zExpire = db_get("cookie-expire","8766"); |
| 312 | 335 | int expires = atoi(zExpire)*3600; |
| 313 | 336 | char *zCode = abbreviated_project_code(db_get("project-code","")); |
| @@ -453,11 +476,11 @@ | ||
| 453 | 476 | |
| 454 | 477 | zOtherRepo = db_text(0, |
| 455 | 478 | "SELECT value FROM config WHERE name='peer-repo-%q'", |
| 456 | 479 | zCode |
| 457 | 480 | ); |
| 458 | - if( zOtherRepo==0 ) return 0; | |
| 481 | + if( zOtherRepo==0 ) return 0; /* No such peer repository */ | |
| 459 | 482 | |
| 460 | 483 | rc = sqlite3_open(zOtherRepo, &pOther); |
| 461 | 484 | if( rc==SQLITE_OK ){ |
| 462 | 485 | zSQL = mprintf( |
| 463 | 486 | "SELECT cexpire FROM user" |
| @@ -512,16 +535,16 @@ | ||
| 512 | 535 | zLogin, zCookie, zRemoteAddr |
| 513 | 536 | ); |
| 514 | 537 | return uid; |
| 515 | 538 | } |
| 516 | 539 | |
| 517 | - | |
| 518 | - | |
| 519 | 540 | /* |
| 520 | 541 | ** This routine examines the login cookie to see if it exists and |
| 521 | 542 | ** and is valid. If the login cookie checks out, it then sets |
| 522 | -** g.zUserUuid appropriately. | |
| 543 | +** global variables appropriately. Global variables set include | |
| 544 | +** g.userUid and g.zLogin and of the g.okRead family of permission | |
| 545 | +** booleans. | |
| 523 | 546 | ** |
| 524 | 547 | */ |
| 525 | 548 | void login_check_credentials(void){ |
| 526 | 549 | int uid = 0; /* User id */ |
| 527 | 550 | const char *zCookie; /* Text of the login cookie */ |
| @@ -529,15 +552,16 @@ | ||
| 529 | 552 | const char *zCap = 0; /* Capability string */ |
| 530 | 553 | |
| 531 | 554 | /* Only run this check once. */ |
| 532 | 555 | if( g.userUid!=0 ) return; |
| 533 | 556 | |
| 534 | - | |
| 535 | 557 | /* If the HTTP connection is coming over 127.0.0.1 and if |
| 536 | 558 | ** local login is disabled and if we are using HTTP and not HTTPS, |
| 537 | 559 | ** then there is no need to check user credentials. |
| 538 | 560 | ** |
| 561 | + ** This feature allows the "fossil ui" command to give the user | |
| 562 | + ** full access rights without having to log in. | |
| 539 | 563 | */ |
| 540 | 564 | zRemoteAddr = ipPrefix(PD("REMOTE_ADDR","nil")); |
| 541 | 565 | if( strcmp(zRemoteAddr, "127.0.0.1")==0 |
| 542 | 566 | && g.useLocalauth |
| 543 | 567 | && db_get_int("localauth",0)==0 |
| @@ -1200,10 +1224,11 @@ | ||
| 1200 | 1224 | |
| 1201 | 1225 | /* Create all the necessary CONFIG table entries on both the |
| 1202 | 1226 | ** other repository and on our own repository. |
| 1203 | 1227 | */ |
| 1204 | 1228 | zSelfProjCode = abbreviated_project_code(zSelfProjCode); |
| 1229 | + zOtherProjCode = abbreviated_project_code(zOtherProjCode); | |
| 1205 | 1230 | db_begin_transaction(); |
| 1206 | 1231 | db_multi_exec( |
| 1207 | 1232 | "DELETE FROM %s.config WHERE name GLOB 'peer-*';" |
| 1208 | 1233 | "INSERT INTO %s.config(name,value) VALUES('peer-repo-%s',%Q);" |
| 1209 | 1234 | "INSERT INTO %s.config(name,value) " |
| 1210 | 1235 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -17,16 +17,20 @@ | |
| 17 | ** |
| 18 | ** This file contains code for generating the login and logout screens. |
| 19 | ** |
| 20 | ** Notes: |
| 21 | ** |
| 22 | ** There are two special-case user-ids: "anonymous" and "nobody". |
| 23 | ** The capabilities of the nobody user are available to anyone, |
| 24 | ** regardless of whether or not they are logged in. The capabilities |
| 25 | ** of anonymous are only available after logging in, but the login |
| 26 | ** screen displays the password for the anonymous login, so this |
| 27 | ** should not prevent a human user from doing so. |
| 28 | ** |
| 29 | ** The nobody user has capabilities that you want spiders to have. |
| 30 | ** The anonymous user has capabilities that you want people without |
| 31 | ** logins to have. |
| 32 | ** |
| @@ -78,11 +82,11 @@ | |
| 78 | /* |
| 79 | ** Return the name of the login cookie. |
| 80 | ** |
| 81 | ** The login cookie name is always of the form: fossil-XXXXXXXXXXXXXXXX |
| 82 | ** where the Xs are the first 16 characters of the login-group-code or |
| 83 | ** the project-code if we are not a member of any login-group. |
| 84 | */ |
| 85 | static char *login_cookie_name(void){ |
| 86 | static char *zCookieName = 0; |
| 87 | if( zCookieName==0 ){ |
| 88 | zCookieName = db_text(0, |
| @@ -107,15 +111,14 @@ | |
| 107 | fossil_redirect_home(); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** The IP address of the client is stored as part of the anonymous |
| 113 | ** login cookie for additional security. But some clients are behind |
| 114 | ** firewalls that shift the IP address with each HTTP request. To |
| 115 | ** allow such (broken) clients to log in, extract just a prefix of the |
| 116 | ** IP address. |
| 117 | */ |
| 118 | static char *ipPrefix(const char *zIP){ |
| 119 | int i, j; |
| 120 | for(i=j=0; zIP[i]; i++){ |
| 121 | if( zIP[i]=='.' ){ |
| @@ -125,11 +128,12 @@ | |
| 125 | } |
| 126 | return mprintf("%.*s", i, zIP); |
| 127 | } |
| 128 | |
| 129 | /* |
| 130 | ** Return an abbreviated project code. |
| 131 | ** |
| 132 | ** Memory is obtained from malloc. |
| 133 | */ |
| 134 | static char *abbreviated_project_code(const char *zFullCode){ |
| 135 | return mprintf("%.16s", zFullCode); |
| @@ -217,15 +221,17 @@ | |
| 217 | login_check_credentials(); |
| 218 | zUsername = P("u"); |
| 219 | zPasswd = P("p"); |
| 220 | anonFlag = P("anon")!=0; |
| 221 | if( P("out")!=0 ){ |
| 222 | const char *zCookieName = login_cookie_name(); |
| 223 | cgi_set_cookie(zCookieName, "", login_cookie_path(), -86400); |
| 224 | redirect_to_g(); |
| 225 | } |
| 226 | if( g.okPassword && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ |
| 227 | zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); |
| 228 | if( db_int(1, "SELECT 0 FROM user" |
| 229 | " WHERE uid=%d AND (pw=%Q OR pw=%Q)", |
| 230 | g.userUid, zPasswd, zSha1Pw) ){ |
| 231 | sleep(1); |
| @@ -264,14 +270,22 @@ | |
| 264 | redirect_to_g(); |
| 265 | return; |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | zIpAddr = PD("REMOTE_ADDR","nil"); |
| 270 | zRemoteAddr = ipPrefix(zIpAddr); |
| 271 | uid = isValidAnonymousLogin(zUsername, zPasswd); |
| 272 | if( uid>0 ){ |
| 273 | char *zNow; /* Current time (julian day number) */ |
| 274 | char *zCookie; /* The login cookie */ |
| 275 | const char *zCookieName; /* Name of the login cookie */ |
| 276 | Blob b; /* Blob used during cookie construction */ |
| 277 | |
| @@ -286,10 +300,12 @@ | |
| 286 | cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), 6*3600); |
| 287 | record_login_attempt("anonymous", zIpAddr, 1); |
| 288 | redirect_to_g(); |
| 289 | } |
| 290 | if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ |
| 291 | zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0); |
| 292 | uid = db_int(0, |
| 293 | "SELECT uid FROM user" |
| 294 | " WHERE login=%Q" |
| 295 | " AND length(cap)>0 AND length(pw)>0" |
| @@ -304,10 +320,17 @@ | |
| 304 | @ You entered an unknown user or an incorrect password. |
| 305 | @ </span></p> |
| 306 | ; |
| 307 | record_login_attempt(zUsername, zIpAddr, 0); |
| 308 | }else{ |
| 309 | char *zCookie; |
| 310 | const char *zCookieName = login_cookie_name(); |
| 311 | const char *zExpire = db_get("cookie-expire","8766"); |
| 312 | int expires = atoi(zExpire)*3600; |
| 313 | char *zCode = abbreviated_project_code(db_get("project-code","")); |
| @@ -453,11 +476,11 @@ | |
| 453 | |
| 454 | zOtherRepo = db_text(0, |
| 455 | "SELECT value FROM config WHERE name='peer-repo-%q'", |
| 456 | zCode |
| 457 | ); |
| 458 | if( zOtherRepo==0 ) return 0; |
| 459 | |
| 460 | rc = sqlite3_open(zOtherRepo, &pOther); |
| 461 | if( rc==SQLITE_OK ){ |
| 462 | zSQL = mprintf( |
| 463 | "SELECT cexpire FROM user" |
| @@ -512,16 +535,16 @@ | |
| 512 | zLogin, zCookie, zRemoteAddr |
| 513 | ); |
| 514 | return uid; |
| 515 | } |
| 516 | |
| 517 | |
| 518 | |
| 519 | /* |
| 520 | ** This routine examines the login cookie to see if it exists and |
| 521 | ** and is valid. If the login cookie checks out, it then sets |
| 522 | ** g.zUserUuid appropriately. |
| 523 | ** |
| 524 | */ |
| 525 | void login_check_credentials(void){ |
| 526 | int uid = 0; /* User id */ |
| 527 | const char *zCookie; /* Text of the login cookie */ |
| @@ -529,15 +552,16 @@ | |
| 529 | const char *zCap = 0; /* Capability string */ |
| 530 | |
| 531 | /* Only run this check once. */ |
| 532 | if( g.userUid!=0 ) return; |
| 533 | |
| 534 | |
| 535 | /* If the HTTP connection is coming over 127.0.0.1 and if |
| 536 | ** local login is disabled and if we are using HTTP and not HTTPS, |
| 537 | ** then there is no need to check user credentials. |
| 538 | ** |
| 539 | */ |
| 540 | zRemoteAddr = ipPrefix(PD("REMOTE_ADDR","nil")); |
| 541 | if( strcmp(zRemoteAddr, "127.0.0.1")==0 |
| 542 | && g.useLocalauth |
| 543 | && db_get_int("localauth",0)==0 |
| @@ -1200,10 +1224,11 @@ | |
| 1200 | |
| 1201 | /* Create all the necessary CONFIG table entries on both the |
| 1202 | ** other repository and on our own repository. |
| 1203 | */ |
| 1204 | zSelfProjCode = abbreviated_project_code(zSelfProjCode); |
| 1205 | db_begin_transaction(); |
| 1206 | db_multi_exec( |
| 1207 | "DELETE FROM %s.config WHERE name GLOB 'peer-*';" |
| 1208 | "INSERT INTO %s.config(name,value) VALUES('peer-repo-%s',%Q);" |
| 1209 | "INSERT INTO %s.config(name,value) " |
| 1210 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -17,16 +17,20 @@ | |
| 17 | ** |
| 18 | ** This file contains code for generating the login and logout screens. |
| 19 | ** |
| 20 | ** Notes: |
| 21 | ** |
| 22 | ** There are four special-case user-ids: "anonymous", "nobody", |
| 23 | ** "developer" and "reader". |
| 24 | ** |
| 25 | ** The capabilities of the nobody user are available to anyone, |
| 26 | ** regardless of whether or not they are logged in. The capabilities |
| 27 | ** of anonymous are only available after logging in, but the login |
| 28 | ** screen displays the password for the anonymous login, so this |
| 29 | ** should not prevent a human user from doing so. The capabilities |
| 30 | ** of developer and reader are inherited by any user that has the |
| 31 | ** "v" and "u" capabilities, respectively. |
| 32 | ** |
| 33 | ** The nobody user has capabilities that you want spiders to have. |
| 34 | ** The anonymous user has capabilities that you want people without |
| 35 | ** logins to have. |
| 36 | ** |
| @@ -78,11 +82,11 @@ | |
| 82 | /* |
| 83 | ** Return the name of the login cookie. |
| 84 | ** |
| 85 | ** The login cookie name is always of the form: fossil-XXXXXXXXXXXXXXXX |
| 86 | ** where the Xs are the first 16 characters of the login-group-code or |
| 87 | ** of the project-code if we are not a member of any login-group. |
| 88 | */ |
| 89 | static char *login_cookie_name(void){ |
| 90 | static char *zCookieName = 0; |
| 91 | if( zCookieName==0 ){ |
| 92 | zCookieName = db_text(0, |
| @@ -107,15 +111,14 @@ | |
| 111 | fossil_redirect_home(); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | ** The IP address of the client is stored as part of login cookies. |
| 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | ** extract just a prefix of the IP address. |
| 120 | */ |
| 121 | static char *ipPrefix(const char *zIP){ |
| 122 | int i, j; |
| 123 | for(i=j=0; zIP[i]; i++){ |
| 124 | if( zIP[i]=='.' ){ |
| @@ -125,11 +128,12 @@ | |
| 128 | } |
| 129 | return mprintf("%.*s", i, zIP); |
| 130 | } |
| 131 | |
| 132 | /* |
| 133 | ** Return an abbreviated project code. The abbreviation is the first |
| 134 | ** 16 characters of the project code. |
| 135 | ** |
| 136 | ** Memory is obtained from malloc. |
| 137 | */ |
| 138 | static char *abbreviated_project_code(const char *zFullCode){ |
| 139 | return mprintf("%.16s", zFullCode); |
| @@ -217,15 +221,17 @@ | |
| 221 | login_check_credentials(); |
| 222 | zUsername = P("u"); |
| 223 | zPasswd = P("p"); |
| 224 | anonFlag = P("anon")!=0; |
| 225 | if( P("out")!=0 ){ |
| 226 | /* To logout, change the cookie value to an empty string */ |
| 227 | const char *zCookieName = login_cookie_name(); |
| 228 | cgi_set_cookie(zCookieName, "", login_cookie_path(), -86400); |
| 229 | redirect_to_g(); |
| 230 | } |
| 231 | if( g.okPassword && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ |
| 232 | /* The user requests a password change */ |
| 233 | zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); |
| 234 | if( db_int(1, "SELECT 0 FROM user" |
| 235 | " WHERE uid=%d AND (pw=%Q OR pw=%Q)", |
| 236 | g.userUid, zPasswd, zSha1Pw) ){ |
| 237 | sleep(1); |
| @@ -264,14 +270,22 @@ | |
| 270 | redirect_to_g(); |
| 271 | return; |
| 272 | } |
| 273 | } |
| 274 | } |
| 275 | zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */ |
| 276 | zRemoteAddr = ipPrefix(zIpAddr); /* Abbreviated IP address */ |
| 277 | uid = isValidAnonymousLogin(zUsername, zPasswd); |
| 278 | if( uid>0 ){ |
| 279 | /* Successful login as anonymous. Set a cookie that looks like |
| 280 | ** this: |
| 281 | ** |
| 282 | ** HASH/TIME/anonymous |
| 283 | ** |
| 284 | ** Where HASH is the sha1sum of TIME/IPADDR/SECRET, in which IPADDR |
| 285 | ** is the abbreviated IP address and SECRET is captcha-secret. |
| 286 | */ |
| 287 | char *zNow; /* Current time (julian day number) */ |
| 288 | char *zCookie; /* The login cookie */ |
| 289 | const char *zCookieName; /* Name of the login cookie */ |
| 290 | Blob b; /* Blob used during cookie construction */ |
| 291 | |
| @@ -286,10 +300,12 @@ | |
| 300 | cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), 6*3600); |
| 301 | record_login_attempt("anonymous", zIpAddr, 1); |
| 302 | redirect_to_g(); |
| 303 | } |
| 304 | if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ |
| 305 | /* Attempting to log in as a user other than anonymous. |
| 306 | */ |
| 307 | zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0); |
| 308 | uid = db_int(0, |
| 309 | "SELECT uid FROM user" |
| 310 | " WHERE login=%Q" |
| 311 | " AND length(cap)>0 AND length(pw)>0" |
| @@ -304,10 +320,17 @@ | |
| 320 | @ You entered an unknown user or an incorrect password. |
| 321 | @ </span></p> |
| 322 | ; |
| 323 | record_login_attempt(zUsername, zIpAddr, 0); |
| 324 | }else{ |
| 325 | /* Non-anonymous login is successful. Set a cookie of the form: |
| 326 | ** |
| 327 | ** HASH/PROJECT/LOGIN |
| 328 | ** |
| 329 | ** where HASH is a random hex number, PROJECT is either project |
| 330 | ** code prefix, and LOGIN is the user name. |
| 331 | */ |
| 332 | char *zCookie; |
| 333 | const char *zCookieName = login_cookie_name(); |
| 334 | const char *zExpire = db_get("cookie-expire","8766"); |
| 335 | int expires = atoi(zExpire)*3600; |
| 336 | char *zCode = abbreviated_project_code(db_get("project-code","")); |
| @@ -453,11 +476,11 @@ | |
| 476 | |
| 477 | zOtherRepo = db_text(0, |
| 478 | "SELECT value FROM config WHERE name='peer-repo-%q'", |
| 479 | zCode |
| 480 | ); |
| 481 | if( zOtherRepo==0 ) return 0; /* No such peer repository */ |
| 482 | |
| 483 | rc = sqlite3_open(zOtherRepo, &pOther); |
| 484 | if( rc==SQLITE_OK ){ |
| 485 | zSQL = mprintf( |
| 486 | "SELECT cexpire FROM user" |
| @@ -512,16 +535,16 @@ | |
| 535 | zLogin, zCookie, zRemoteAddr |
| 536 | ); |
| 537 | return uid; |
| 538 | } |
| 539 | |
| 540 | /* |
| 541 | ** This routine examines the login cookie to see if it exists and |
| 542 | ** and is valid. If the login cookie checks out, it then sets |
| 543 | ** global variables appropriately. Global variables set include |
| 544 | ** g.userUid and g.zLogin and of the g.okRead family of permission |
| 545 | ** booleans. |
| 546 | ** |
| 547 | */ |
| 548 | void login_check_credentials(void){ |
| 549 | int uid = 0; /* User id */ |
| 550 | const char *zCookie; /* Text of the login cookie */ |
| @@ -529,15 +552,16 @@ | |
| 552 | const char *zCap = 0; /* Capability string */ |
| 553 | |
| 554 | /* Only run this check once. */ |
| 555 | if( g.userUid!=0 ) return; |
| 556 | |
| 557 | /* If the HTTP connection is coming over 127.0.0.1 and if |
| 558 | ** local login is disabled and if we are using HTTP and not HTTPS, |
| 559 | ** then there is no need to check user credentials. |
| 560 | ** |
| 561 | ** This feature allows the "fossil ui" command to give the user |
| 562 | ** full access rights without having to log in. |
| 563 | */ |
| 564 | zRemoteAddr = ipPrefix(PD("REMOTE_ADDR","nil")); |
| 565 | if( strcmp(zRemoteAddr, "127.0.0.1")==0 |
| 566 | && g.useLocalauth |
| 567 | && db_get_int("localauth",0)==0 |
| @@ -1200,10 +1224,11 @@ | |
| 1224 | |
| 1225 | /* Create all the necessary CONFIG table entries on both the |
| 1226 | ** other repository and on our own repository. |
| 1227 | */ |
| 1228 | zSelfProjCode = abbreviated_project_code(zSelfProjCode); |
| 1229 | zOtherProjCode = abbreviated_project_code(zOtherProjCode); |
| 1230 | db_begin_transaction(); |
| 1231 | db_multi_exec( |
| 1232 | "DELETE FROM %s.config WHERE name GLOB 'peer-*';" |
| 1233 | "INSERT INTO %s.config(name,value) VALUES('peer-repo-%s',%Q);" |
| 1234 | "INSERT INTO %s.config(name,value) " |
| 1235 |