Fossil SCM

Update the sub-repository capability so that it is able to restrict permissions on the sub-repository to a subset of the login permissions.

drh 2011-03-28 21:27 UTC sub-repos
Commit c477b2470f552fe46bf269ba2cc722d3f7980f89
2 files changed +87 -4 +14 -3
+87 -4
--- src/login.c
+++ src/login.c
@@ -500,27 +500,32 @@
500500
/* Set the capabilities */
501501
login_set_capabilities(zCap);
502502
login_set_anon_nobody_capabilities();
503503
}
504504
505
+/*
506
+** Memory of settings
507
+*/
508
+static int login_anon_once = 1;
509
+static char login_settings[26];
510
+
505511
/*
506512
** Add the default privileges of users "nobody" and "anonymous" as appropriate
507513
** for the user g.zLogin.
508514
*/
509515
void login_set_anon_nobody_capabilities(void){
510
- static int once = 1;
511
- if( g.zLogin && once ){
516
+ if( g.zLogin && login_anon_once ){
512517
const char *zCap;
513518
/* All logged-in users inherit privileges from "nobody" */
514519
zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
515520
login_set_capabilities(zCap);
516521
if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
517522
/* All logged-in users inherit privileges from "anonymous" */
518523
zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
519524
login_set_capabilities(zCap);
520525
}
521
- once = 0;
526
+ login_anon_once = 0;
522527
}
523528
}
524529
525530
/*
526531
** Set the global capability flags based on a capability string.
@@ -528,10 +533,13 @@
528533
void login_set_capabilities(const char *zCap){
529534
static char *zDev = 0;
530535
static char *zUser = 0;
531536
int i;
532537
for(i=0; zCap[i]; i++){
538
+ int c = zCap[i];
539
+ if( c<'a' || c>'z' ) continue;
540
+ login_settings[c-'a'] = 1;
533541
switch( zCap[i] ){
534542
case 's': g.okSetup = 1; /* Fall thru into Admin */
535543
case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip =
536544
g.okRdWiki = g.okWrWiki = g.okNewWiki =
537545
g.okApndWiki = g.okHistory = g.okClone =
@@ -617,18 +625,93 @@
617625
case 's': rc = g.okSetup; break;
618626
case 't': rc = g.okTktFmt; break;
619627
/* case 'u': READER */
620628
/* case 'v': DEVELOPER */
621629
case 'w': rc = g.okWrTkt; break;
622
- /* case 'x': */
630
+ case 'x': rc = g.okPrivate; break;
623631
/* case 'y': */
624632
case 'z': rc = g.okZip; break;
625633
default: rc = 0; break;
626634
}
627635
}
628636
return rc;
629637
}
638
+
639
+/*
640
+** For every character in zCap between 'a' and 'z' set a byte in seen[].
641
+*/
642
+static void setCap(const char *zCap, char *seen){
643
+ int c;
644
+ if( zCap ){
645
+ while( (c = *(zCap++))!=0 ){
646
+ if( c>='a' && c<='z' ) seen[c-'a'] = 1;
647
+ }
648
+ }
649
+}
650
+
651
+/*
652
+** Remove privileges such that previleges are restricted to the
653
+** set given in the argument.
654
+*/
655
+void login_restrict_capabilities(const char *zAllowed){
656
+ char zNew[30];
657
+ char seen[26];
658
+ int nNew = 0;
659
+ int i;
660
+
661
+ /* Compute the intersection of current settings with zAllowed[] and
662
+ ** store the result in zNew[]
663
+ */
664
+ memset(seen, 0, sizeof(seen));
665
+ setCap(zAllowed, seen);
666
+ if( seen['v'-'a'] ){
667
+ char *z = db_text(0, "SELECT cap FROM user WHERE login='developer'");
668
+ setCap(z, seen);
669
+ fossil_free(z);
670
+ }
671
+ if( seen['u'-'a'] ){
672
+ char *z = db_text(0, "SELECT cap FROM user WHERE login='reader'");
673
+ setCap(z, seen);
674
+ fossil_free(z);
675
+ }
676
+ seen['u'-'a'] = 0;
677
+ seen['v'-'a'] = 0;
678
+ for(i=0; i<sizeof(seen); i++){
679
+ if( seen[i] && login_settings[i] ) zNew[nNew++] = i+'a';
680
+ }
681
+ zNew[nNew] = 0;
682
+
683
+ /* Turn off all capabilities */
684
+ g.okSetup = 0;
685
+ g.okAdmin = 0;
686
+ g.okDelete = 0;
687
+ g.okPassword = 0;
688
+ g.okQuery = 0;
689
+ g.okWrite = 0;
690
+ g.okRead = 0;
691
+ g.okHistory = 0;
692
+ g.okClone = 0;
693
+ g.okRdWiki = 0;
694
+ g.okNewWiki = 0;
695
+ g.okApndWiki = 0;
696
+ g.okWrWiki = 0;
697
+ g.okRdTkt = 0;
698
+ g.okNewTkt = 0;
699
+ g.okApndTkt = 0;
700
+ g.okWrTkt = 0;
701
+ g.okAttach = 0;
702
+ g.okTktFmt = 0;
703
+ g.okRdAddr = 0;
704
+ g.okZip = 0;
705
+ g.okPrivate = 0;
706
+ memset(login_settings, 0, sizeof(login_settings));
707
+
708
+ /* Set the reduced capabilities */
709
+ login_set_capabilities(zNew);
710
+ login_anon_once = 1;
711
+ login_set_anon_nobody_capabilities();
712
+}
630713
631714
/*
632715
** Call this routine when the credential check fails. It causes
633716
** a redirect to the "login" page.
634717
*/
635718
--- src/login.c
+++ src/login.c
@@ -500,27 +500,32 @@
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.
@@ -528,10 +533,13 @@
528 void login_set_capabilities(const char *zCap){
529 static char *zDev = 0;
530 static char *zUser = 0;
531 int i;
532 for(i=0; zCap[i]; i++){
 
 
 
533 switch( zCap[i] ){
534 case 's': g.okSetup = 1; /* Fall thru into Admin */
535 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip =
536 g.okRdWiki = g.okWrWiki = g.okNewWiki =
537 g.okApndWiki = g.okHistory = g.okClone =
@@ -617,18 +625,93 @@
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,32 @@
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 static char login_settings[26];
510
511 /*
512 ** Add the default privileges of users "nobody" and "anonymous" as appropriate
513 ** for the user g.zLogin.
514 */
515 void login_set_anon_nobody_capabilities(void){
516 if( g.zLogin && login_anon_once ){
 
517 const char *zCap;
518 /* All logged-in users inherit privileges from "nobody" */
519 zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
520 login_set_capabilities(zCap);
521 if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
522 /* All logged-in users inherit privileges from "anonymous" */
523 zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
524 login_set_capabilities(zCap);
525 }
526 login_anon_once = 0;
527 }
528 }
529
530 /*
531 ** Set the global capability flags based on a capability string.
@@ -528,10 +533,13 @@
533 void login_set_capabilities(const char *zCap){
534 static char *zDev = 0;
535 static char *zUser = 0;
536 int i;
537 for(i=0; zCap[i]; i++){
538 int c = zCap[i];
539 if( c<'a' || c>'z' ) continue;
540 login_settings[c-'a'] = 1;
541 switch( zCap[i] ){
542 case 's': g.okSetup = 1; /* Fall thru into Admin */
543 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip =
544 g.okRdWiki = g.okWrWiki = g.okNewWiki =
545 g.okApndWiki = g.okHistory = g.okClone =
@@ -617,18 +625,93 @@
625 case 's': rc = g.okSetup; break;
626 case 't': rc = g.okTktFmt; break;
627 /* case 'u': READER */
628 /* case 'v': DEVELOPER */
629 case 'w': rc = g.okWrTkt; break;
630 case 'x': rc = g.okPrivate; break;
631 /* case 'y': */
632 case 'z': rc = g.okZip; break;
633 default: rc = 0; break;
634 }
635 }
636 return rc;
637 }
638
639 /*
640 ** For every character in zCap between 'a' and 'z' set a byte in seen[].
641 */
642 static void setCap(const char *zCap, char *seen){
643 int c;
644 if( zCap ){
645 while( (c = *(zCap++))!=0 ){
646 if( c>='a' && c<='z' ) seen[c-'a'] = 1;
647 }
648 }
649 }
650
651 /*
652 ** Remove privileges such that previleges are restricted to the
653 ** set given in the argument.
654 */
655 void login_restrict_capabilities(const char *zAllowed){
656 char zNew[30];
657 char seen[26];
658 int nNew = 0;
659 int i;
660
661 /* Compute the intersection of current settings with zAllowed[] and
662 ** store the result in zNew[]
663 */
664 memset(seen, 0, sizeof(seen));
665 setCap(zAllowed, seen);
666 if( seen['v'-'a'] ){
667 char *z = db_text(0, "SELECT cap FROM user WHERE login='developer'");
668 setCap(z, seen);
669 fossil_free(z);
670 }
671 if( seen['u'-'a'] ){
672 char *z = db_text(0, "SELECT cap FROM user WHERE login='reader'");
673 setCap(z, seen);
674 fossil_free(z);
675 }
676 seen['u'-'a'] = 0;
677 seen['v'-'a'] = 0;
678 for(i=0; i<sizeof(seen); i++){
679 if( seen[i] && login_settings[i] ) zNew[nNew++] = i+'a';
680 }
681 zNew[nNew] = 0;
682
683 /* Turn off all capabilities */
684 g.okSetup = 0;
685 g.okAdmin = 0;
686 g.okDelete = 0;
687 g.okPassword = 0;
688 g.okQuery = 0;
689 g.okWrite = 0;
690 g.okRead = 0;
691 g.okHistory = 0;
692 g.okClone = 0;
693 g.okRdWiki = 0;
694 g.okNewWiki = 0;
695 g.okApndWiki = 0;
696 g.okWrWiki = 0;
697 g.okRdTkt = 0;
698 g.okNewTkt = 0;
699 g.okApndTkt = 0;
700 g.okWrTkt = 0;
701 g.okAttach = 0;
702 g.okTktFmt = 0;
703 g.okRdAddr = 0;
704 g.okZip = 0;
705 g.okPrivate = 0;
706 memset(login_settings, 0, sizeof(login_settings));
707
708 /* Set the reduced capabilities */
709 login_set_capabilities(zNew);
710 login_anon_once = 1;
711 login_set_anon_nobody_capabilities();
712 }
713
714 /*
715 ** Call this routine when the credential check fails. It causes
716 ** a redirect to the "login" page.
717 */
718
+14 -3
--- src/main.c
+++ src/main.c
@@ -983,24 +983,35 @@
983983
984984
/* Look for sub-repositories. A sub-repository is another repository
985985
** that accepts the login credentials of the current repository. A
986986
** subrepository is identified by a CONFIG table entry "subrepo:NAME"
987987
** where NAME is the first component of the path. The value of the
988
- ** the CONFIG entries is the name of the repository.
988
+ ** the CONFIG entries is the string "CAP:FILENAME" where CAP is the
989
+ ** maximum capability string and FILENAME is the new repository
990
+ ** filename.
989991
*/
990992
zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'",
991993
g.zPath);
992994
if( zAltRepo ){
993995
int nHost;
996
+ int jj;
997
+ char *zInheritCap = zAltRepo;
994998
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
+ zInheritCap = "";
1005
+ }
9951006
if( zAltRepo[0]!='/' ){
996
- zAltRepo = mprintf("%s/../%z", g.zRepositoryName, zAltRepo);
1007
+ zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
9971008
file_simplify_name(zAltRepo, -1);
9981009
}
9991010
db_close(1);
10001011
db_open_repository(zAltRepo);
1001
- fossil_free(zAltRepo);
1012
+ login_restrict_capabilities(zInheritCap);
10021013
zPath += i;
10031014
nHost = g.zTop - g.zBaseURL;
10041015
g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
10051016
g.zTop = g.zBaseURL + nHost;
10061017
continue;
10071018
--- src/main.c
+++ src/main.c
@@ -983,24 +983,35 @@
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 name of the repository.
 
 
989 */
990 zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'",
991 g.zPath);
992 if( zAltRepo ){
993 int nHost;
 
 
994 login_check_credentials();
 
 
 
 
 
 
 
995 if( zAltRepo[0]!='/' ){
996 zAltRepo = mprintf("%s/../%z", g.zRepositoryName, zAltRepo);
997 file_simplify_name(zAltRepo, -1);
998 }
999 db_close(1);
1000 db_open_repository(zAltRepo);
1001 fossil_free(zAltRepo);
1002 zPath += i;
1003 nHost = g.zTop - g.zBaseURL;
1004 g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
1005 g.zTop = g.zBaseURL + nHost;
1006 continue;
1007
--- src/main.c
+++ src/main.c
@@ -983,24 +983,35 @@
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 "CAP:FILENAME" where CAP is the
989 ** maximum capability string and FILENAME is the new repository
990 ** 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 *zInheritCap = 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 zInheritCap = "";
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_restrict_capabilities(zInheritCap);
1013 zPath += i;
1014 nHost = g.zTop - g.zBaseURL;
1015 g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
1016 g.zTop = g.zBaseURL + nHost;
1017 continue;
1018

Keyboard Shortcuts

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