Fossil SCM
Merge the sub-repo capability into trunk.
Commit
ab4882588e9bb6adcaced5dbce1344758034a243
Parent
13ceb46e49d28ab…
2 files changed
+58
-4
+50
-8
+58
-4
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -500,27 +500,31 @@ | ||
| 500 | 500 | /* Set the capabilities */ |
| 501 | 501 | login_set_capabilities(zCap); |
| 502 | 502 | login_set_anon_nobody_capabilities(); |
| 503 | 503 | } |
| 504 | 504 | |
| 505 | +/* | |
| 506 | +** Memory of settings | |
| 507 | +*/ | |
| 508 | +static int login_anon_once = 1; | |
| 509 | + | |
| 505 | 510 | /* |
| 506 | 511 | ** Add the default privileges of users "nobody" and "anonymous" as appropriate |
| 507 | 512 | ** for the user g.zLogin. |
| 508 | 513 | */ |
| 509 | 514 | void login_set_anon_nobody_capabilities(void){ |
| 510 | - static int once = 1; | |
| 511 | - if( g.zLogin && once ){ | |
| 515 | + if( g.zLogin && login_anon_once ){ | |
| 512 | 516 | const char *zCap; |
| 513 | 517 | /* All logged-in users inherit privileges from "nobody" */ |
| 514 | 518 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 515 | 519 | login_set_capabilities(zCap); |
| 516 | 520 | if( fossil_strcmp(g.zLogin, "nobody")!=0 ){ |
| 517 | 521 | /* All logged-in users inherit privileges from "anonymous" */ |
| 518 | 522 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 519 | 523 | login_set_capabilities(zCap); |
| 520 | 524 | } |
| 521 | - once = 0; | |
| 525 | + login_anon_once = 0; | |
| 522 | 526 | } |
| 523 | 527 | } |
| 524 | 528 | |
| 525 | 529 | /* |
| 526 | 530 | ** Set the global capability flags based on a capability string. |
| @@ -617,18 +621,68 @@ | ||
| 617 | 621 | case 's': rc = g.okSetup; break; |
| 618 | 622 | case 't': rc = g.okTktFmt; break; |
| 619 | 623 | /* case 'u': READER */ |
| 620 | 624 | /* case 'v': DEVELOPER */ |
| 621 | 625 | case 'w': rc = g.okWrTkt; break; |
| 622 | - /* case 'x': */ | |
| 626 | + case 'x': rc = g.okPrivate; break; | |
| 623 | 627 | /* case 'y': */ |
| 624 | 628 | case 'z': rc = g.okZip; break; |
| 625 | 629 | default: rc = 0; break; |
| 626 | 630 | } |
| 627 | 631 | } |
| 628 | 632 | return rc; |
| 629 | 633 | } |
| 634 | + | |
| 635 | +/* | |
| 636 | +** Change the login to zUser. | |
| 637 | +*/ | |
| 638 | +void login_as_user(const char *zUser){ | |
| 639 | + char *zCap = ""; /* New capabilities */ | |
| 640 | + | |
| 641 | + /* Turn off all capabilities from prior logins */ | |
| 642 | + g.okSetup = 0; | |
| 643 | + g.okAdmin = 0; | |
| 644 | + g.okDelete = 0; | |
| 645 | + g.okPassword = 0; | |
| 646 | + g.okQuery = 0; | |
| 647 | + g.okWrite = 0; | |
| 648 | + g.okRead = 0; | |
| 649 | + g.okHistory = 0; | |
| 650 | + g.okClone = 0; | |
| 651 | + g.okRdWiki = 0; | |
| 652 | + g.okNewWiki = 0; | |
| 653 | + g.okApndWiki = 0; | |
| 654 | + g.okWrWiki = 0; | |
| 655 | + g.okRdTkt = 0; | |
| 656 | + g.okNewTkt = 0; | |
| 657 | + g.okApndTkt = 0; | |
| 658 | + g.okWrTkt = 0; | |
| 659 | + g.okAttach = 0; | |
| 660 | + g.okTktFmt = 0; | |
| 661 | + g.okRdAddr = 0; | |
| 662 | + g.okZip = 0; | |
| 663 | + g.okPrivate = 0; | |
| 664 | + | |
| 665 | + /* Set the global variables recording the userid and login. The | |
| 666 | + ** "nobody" user is a special case in that g.zLogin==0. | |
| 667 | + */ | |
| 668 | + g.userUid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUser); | |
| 669 | + if( g.userUid==0 ){ | |
| 670 | + zUser = 0; | |
| 671 | + g.userUid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); | |
| 672 | + } | |
| 673 | + if( g.userUid ){ | |
| 674 | + zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", g.userUid); | |
| 675 | + } | |
| 676 | + if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0; | |
| 677 | + g.zLogin = fossil_strdup(zUser); | |
| 678 | + | |
| 679 | + /* Set the capabilities */ | |
| 680 | + login_set_capabilities(zCap); | |
| 681 | + login_anon_once = 1; | |
| 682 | + login_set_anon_nobody_capabilities(); | |
| 683 | +} | |
| 630 | 684 | |
| 631 | 685 | /* |
| 632 | 686 | ** Call this routine when the credential check fails. It causes |
| 633 | 687 | ** a redirect to the "login" page. |
| 634 | 688 | */ |
| 635 | 689 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -500,27 +500,31 @@ | |
| 500 | /* Set the capabilities */ |
| 501 | login_set_capabilities(zCap); |
| 502 | login_set_anon_nobody_capabilities(); |
| 503 | } |
| 504 | |
| 505 | /* |
| 506 | ** Add the default privileges of users "nobody" and "anonymous" as appropriate |
| 507 | ** for the user g.zLogin. |
| 508 | */ |
| 509 | void login_set_anon_nobody_capabilities(void){ |
| 510 | static int once = 1; |
| 511 | if( g.zLogin && once ){ |
| 512 | const char *zCap; |
| 513 | /* All logged-in users inherit privileges from "nobody" */ |
| 514 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 515 | login_set_capabilities(zCap); |
| 516 | if( fossil_strcmp(g.zLogin, "nobody")!=0 ){ |
| 517 | /* All logged-in users inherit privileges from "anonymous" */ |
| 518 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 519 | login_set_capabilities(zCap); |
| 520 | } |
| 521 | once = 0; |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | /* |
| 526 | ** Set the global capability flags based on a capability string. |
| @@ -617,18 +621,68 @@ | |
| 617 | case 's': rc = g.okSetup; break; |
| 618 | case 't': rc = g.okTktFmt; break; |
| 619 | /* case 'u': READER */ |
| 620 | /* case 'v': DEVELOPER */ |
| 621 | case 'w': rc = g.okWrTkt; break; |
| 622 | /* case 'x': */ |
| 623 | /* case 'y': */ |
| 624 | case 'z': rc = g.okZip; break; |
| 625 | default: rc = 0; break; |
| 626 | } |
| 627 | } |
| 628 | return rc; |
| 629 | } |
| 630 | |
| 631 | /* |
| 632 | ** Call this routine when the credential check fails. It causes |
| 633 | ** a redirect to the "login" page. |
| 634 | */ |
| 635 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -500,27 +500,31 @@ | |
| 500 | /* Set the capabilities */ |
| 501 | login_set_capabilities(zCap); |
| 502 | login_set_anon_nobody_capabilities(); |
| 503 | } |
| 504 | |
| 505 | /* |
| 506 | ** Memory of settings |
| 507 | */ |
| 508 | static int login_anon_once = 1; |
| 509 | |
| 510 | /* |
| 511 | ** Add the default privileges of users "nobody" and "anonymous" as appropriate |
| 512 | ** for the user g.zLogin. |
| 513 | */ |
| 514 | void login_set_anon_nobody_capabilities(void){ |
| 515 | if( g.zLogin && login_anon_once ){ |
| 516 | const char *zCap; |
| 517 | /* All logged-in users inherit privileges from "nobody" */ |
| 518 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 519 | login_set_capabilities(zCap); |
| 520 | if( fossil_strcmp(g.zLogin, "nobody")!=0 ){ |
| 521 | /* All logged-in users inherit privileges from "anonymous" */ |
| 522 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 523 | login_set_capabilities(zCap); |
| 524 | } |
| 525 | login_anon_once = 0; |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | /* |
| 530 | ** Set the global capability flags based on a capability string. |
| @@ -617,18 +621,68 @@ | |
| 621 | case 's': rc = g.okSetup; break; |
| 622 | case 't': rc = g.okTktFmt; break; |
| 623 | /* case 'u': READER */ |
| 624 | /* case 'v': DEVELOPER */ |
| 625 | case 'w': rc = g.okWrTkt; break; |
| 626 | case 'x': rc = g.okPrivate; break; |
| 627 | /* case 'y': */ |
| 628 | case 'z': rc = g.okZip; break; |
| 629 | default: rc = 0; break; |
| 630 | } |
| 631 | } |
| 632 | return rc; |
| 633 | } |
| 634 | |
| 635 | /* |
| 636 | ** Change the login to zUser. |
| 637 | */ |
| 638 | void login_as_user(const char *zUser){ |
| 639 | char *zCap = ""; /* New capabilities */ |
| 640 | |
| 641 | /* Turn off all capabilities from prior logins */ |
| 642 | g.okSetup = 0; |
| 643 | g.okAdmin = 0; |
| 644 | g.okDelete = 0; |
| 645 | g.okPassword = 0; |
| 646 | g.okQuery = 0; |
| 647 | g.okWrite = 0; |
| 648 | g.okRead = 0; |
| 649 | g.okHistory = 0; |
| 650 | g.okClone = 0; |
| 651 | g.okRdWiki = 0; |
| 652 | g.okNewWiki = 0; |
| 653 | g.okApndWiki = 0; |
| 654 | g.okWrWiki = 0; |
| 655 | g.okRdTkt = 0; |
| 656 | g.okNewTkt = 0; |
| 657 | g.okApndTkt = 0; |
| 658 | g.okWrTkt = 0; |
| 659 | g.okAttach = 0; |
| 660 | g.okTktFmt = 0; |
| 661 | g.okRdAddr = 0; |
| 662 | g.okZip = 0; |
| 663 | g.okPrivate = 0; |
| 664 | |
| 665 | /* Set the global variables recording the userid and login. The |
| 666 | ** "nobody" user is a special case in that g.zLogin==0. |
| 667 | */ |
| 668 | g.userUid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUser); |
| 669 | if( g.userUid==0 ){ |
| 670 | zUser = 0; |
| 671 | g.userUid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); |
| 672 | } |
| 673 | if( g.userUid ){ |
| 674 | zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", g.userUid); |
| 675 | } |
| 676 | if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0; |
| 677 | g.zLogin = fossil_strdup(zUser); |
| 678 | |
| 679 | /* Set the capabilities */ |
| 680 | login_set_capabilities(zCap); |
| 681 | login_anon_once = 1; |
| 682 | login_set_anon_nobody_capabilities(); |
| 683 | } |
| 684 | |
| 685 | /* |
| 686 | ** Call this routine when the credential check fails. It causes |
| 687 | ** a redirect to the "login" page. |
| 688 | */ |
| 689 |
+50
-8
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -968,19 +968,61 @@ | ||
| 968 | 968 | fossil_redirect_home(); |
| 969 | 969 | }else{ |
| 970 | 970 | zPath = mprintf("%s", zPathInfo); |
| 971 | 971 | } |
| 972 | 972 | |
| 973 | - /* Remove the leading "/" at the beginning of the path. | |
| 973 | + /* Make g.zPath point to the first element of the path. Make | |
| 974 | + ** g.zExtra point to everything past that point. | |
| 974 | 975 | */ |
| 975 | - g.zPath = &zPath[1]; | |
| 976 | - for(i=1; zPath[i] && zPath[i]!='/'; i++){} | |
| 977 | - if( zPath[i]=='/' ){ | |
| 978 | - zPath[i] = 0; | |
| 979 | - g.zExtra = &zPath[i+1]; | |
| 980 | - }else{ | |
| 981 | - g.zExtra = 0; | |
| 976 | + while(1){ | |
| 977 | + char *zAltRepo = 0; | |
| 978 | + g.zPath = &zPath[1]; | |
| 979 | + for(i=1; zPath[i] && zPath[i]!='/'; i++){} | |
| 980 | + if( zPath[i]=='/' ){ | |
| 981 | + zPath[i] = 0; | |
| 982 | + g.zExtra = &zPath[i+1]; | |
| 983 | + | |
| 984 | + /* Look for sub-repositories. A sub-repository is another repository | |
| 985 | + ** that accepts the login credentials of the current repository. A | |
| 986 | + ** subrepository is identified by a CONFIG table entry "subrepo:NAME" | |
| 987 | + ** where NAME is the first component of the path. The value of the | |
| 988 | + ** the CONFIG entries is the string "USER:FILENAME" where USER is the | |
| 989 | + ** USER name to log in as in the subrepository and FILENAME is the | |
| 990 | + ** repository filename. | |
| 991 | + */ | |
| 992 | + zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'", | |
| 993 | + g.zPath); | |
| 994 | + if( zAltRepo ){ | |
| 995 | + int nHost; | |
| 996 | + int jj; | |
| 997 | + char *zUser = zAltRepo; | |
| 998 | + login_check_credentials(); | |
| 999 | + for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){} | |
| 1000 | + if( zAltRepo[jj]==':' ){ | |
| 1001 | + zAltRepo[jj] = 0; | |
| 1002 | + zAltRepo += jj+1; | |
| 1003 | + }else{ | |
| 1004 | + zUser = "nobody"; | |
| 1005 | + } | |
| 1006 | + if( zAltRepo[0]!='/' ){ | |
| 1007 | + zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); | |
| 1008 | + file_simplify_name(zAltRepo, -1); | |
| 1009 | + } | |
| 1010 | + db_close(1); | |
| 1011 | + db_open_repository(zAltRepo); | |
| 1012 | + login_as_user(zUser); | |
| 1013 | + g.okPassword = 0; | |
| 1014 | + zPath += i; | |
| 1015 | + nHost = g.zTop - g.zBaseURL; | |
| 1016 | + g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath); | |
| 1017 | + g.zTop = g.zBaseURL + nHost; | |
| 1018 | + continue; | |
| 1019 | + } | |
| 1020 | + }else{ | |
| 1021 | + g.zExtra = 0; | |
| 1022 | + } | |
| 1023 | + break; | |
| 982 | 1024 | } |
| 983 | 1025 | if( g.zExtra ){ |
| 984 | 1026 | /* CGI parameters get this treatment elsewhere, but places like getfile |
| 985 | 1027 | ** will use g.zExtra directly. |
| 986 | 1028 | */ |
| 987 | 1029 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -968,19 +968,61 @@ | |
| 968 | fossil_redirect_home(); |
| 969 | }else{ |
| 970 | zPath = mprintf("%s", zPathInfo); |
| 971 | } |
| 972 | |
| 973 | /* Remove the leading "/" at the beginning of the path. |
| 974 | */ |
| 975 | g.zPath = &zPath[1]; |
| 976 | for(i=1; zPath[i] && zPath[i]!='/'; i++){} |
| 977 | if( zPath[i]=='/' ){ |
| 978 | zPath[i] = 0; |
| 979 | g.zExtra = &zPath[i+1]; |
| 980 | }else{ |
| 981 | g.zExtra = 0; |
| 982 | } |
| 983 | if( g.zExtra ){ |
| 984 | /* CGI parameters get this treatment elsewhere, but places like getfile |
| 985 | ** will use g.zExtra directly. |
| 986 | */ |
| 987 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -968,19 +968,61 @@ | |
| 968 | fossil_redirect_home(); |
| 969 | }else{ |
| 970 | zPath = mprintf("%s", zPathInfo); |
| 971 | } |
| 972 | |
| 973 | /* Make g.zPath point to the first element of the path. Make |
| 974 | ** g.zExtra point to everything past that point. |
| 975 | */ |
| 976 | while(1){ |
| 977 | char *zAltRepo = 0; |
| 978 | g.zPath = &zPath[1]; |
| 979 | for(i=1; zPath[i] && zPath[i]!='/'; i++){} |
| 980 | if( zPath[i]=='/' ){ |
| 981 | zPath[i] = 0; |
| 982 | g.zExtra = &zPath[i+1]; |
| 983 | |
| 984 | /* Look for sub-repositories. A sub-repository is another repository |
| 985 | ** that accepts the login credentials of the current repository. A |
| 986 | ** subrepository is identified by a CONFIG table entry "subrepo:NAME" |
| 987 | ** where NAME is the first component of the path. The value of the |
| 988 | ** the CONFIG entries is the string "USER:FILENAME" where USER is the |
| 989 | ** USER name to log in as in the subrepository and FILENAME is the |
| 990 | ** repository filename. |
| 991 | */ |
| 992 | zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'", |
| 993 | g.zPath); |
| 994 | if( zAltRepo ){ |
| 995 | int nHost; |
| 996 | int jj; |
| 997 | char *zUser = zAltRepo; |
| 998 | login_check_credentials(); |
| 999 | for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){} |
| 1000 | if( zAltRepo[jj]==':' ){ |
| 1001 | zAltRepo[jj] = 0; |
| 1002 | zAltRepo += jj+1; |
| 1003 | }else{ |
| 1004 | zUser = "nobody"; |
| 1005 | } |
| 1006 | if( zAltRepo[0]!='/' ){ |
| 1007 | zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); |
| 1008 | file_simplify_name(zAltRepo, -1); |
| 1009 | } |
| 1010 | db_close(1); |
| 1011 | db_open_repository(zAltRepo); |
| 1012 | login_as_user(zUser); |
| 1013 | g.okPassword = 0; |
| 1014 | zPath += i; |
| 1015 | nHost = g.zTop - g.zBaseURL; |
| 1016 | g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath); |
| 1017 | g.zTop = g.zBaseURL + nHost; |
| 1018 | continue; |
| 1019 | } |
| 1020 | }else{ |
| 1021 | g.zExtra = 0; |
| 1022 | } |
| 1023 | break; |
| 1024 | } |
| 1025 | if( g.zExtra ){ |
| 1026 | /* CGI parameters get this treatment elsewhere, but places like getfile |
| 1027 | ** will use g.zExtra directly. |
| 1028 | */ |
| 1029 |