Fossil

Check-in [c477b2470f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Update the sub-repository capability so that it is able to restrict permissions on the sub-repository to a subset of the login permissions.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | sub-repos
Files: files | file ages | folders
SHA1: c477b2470f552fe46bf269ba2cc722d3f7980f89
User & Date: drh 2011-03-28 21:27:37.154
Context
2011-03-28
21:46
Fixes to the capability reduction on subrepositories. check-in: 4b545a8a02 user: drh tags: sub-repos
21:27
Update the sub-repository capability so that it is able to restrict permissions on the sub-repository to a subset of the login permissions. check-in: c477b2470f user: drh tags: sub-repos
18:08
Allow for the creation of "sub-repositories" that can be accessed through the web interface using the same login credentials as the parent repository. check-in: 97d0118794 user: drh tags: sub-repos
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/login.c.
498
499
500
501
502
503
504






505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532



533
534
535
536
537
538
539
  }

  /* Set the capabilities */
  login_set_capabilities(zCap);
  login_set_anon_nobody_capabilities();
}







/*
** Add the default privileges of users "nobody" and "anonymous" as appropriate
** for the user g.zLogin.
*/
void login_set_anon_nobody_capabilities(void){
  static int once = 1;
  if( g.zLogin && once ){
    const char *zCap;
    /* All logged-in users inherit privileges from "nobody" */
    zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
    login_set_capabilities(zCap);
    if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
      /* All logged-in users inherit privileges from "anonymous" */
      zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
      login_set_capabilities(zCap);
    }
    once = 0;
  }
}

/*
** Set the global capability flags based on a capability string.
*/
void login_set_capabilities(const char *zCap){
  static char *zDev = 0;
  static char *zUser = 0;
  int i;
  for(i=0; zCap[i]; i++){



    switch( zCap[i] ){
      case 's':   g.okSetup = 1;  /* Fall thru into Admin */
      case 'a':   g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip =
                              g.okRdWiki = g.okWrWiki = g.okNewWiki =
                              g.okApndWiki = g.okHistory = g.okClone = 
                              g.okNewTkt = g.okPassword = g.okRdAddr =
                              g.okTktFmt = g.okAttach = g.okApndTkt = 1;







>
>
>
>
>
>





<
|









|











>
>
>







498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515

516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  }

  /* Set the capabilities */
  login_set_capabilities(zCap);
  login_set_anon_nobody_capabilities();
}

/*
** Memory of settings
*/
static int login_anon_once = 1;
static char login_settings[26];

/*
** Add the default privileges of users "nobody" and "anonymous" as appropriate
** for the user g.zLogin.
*/
void login_set_anon_nobody_capabilities(void){

  if( g.zLogin && login_anon_once ){
    const char *zCap;
    /* All logged-in users inherit privileges from "nobody" */
    zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
    login_set_capabilities(zCap);
    if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
      /* All logged-in users inherit privileges from "anonymous" */
      zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
      login_set_capabilities(zCap);
    }
    login_anon_once = 0;
  }
}

/*
** Set the global capability flags based on a capability string.
*/
void login_set_capabilities(const char *zCap){
  static char *zDev = 0;
  static char *zUser = 0;
  int i;
  for(i=0; zCap[i]; i++){
    int c = zCap[i];
    if( c<'a' || c>'z' ) continue;
    login_settings[c-'a'] = 1;
    switch( zCap[i] ){
      case 's':   g.okSetup = 1;  /* Fall thru into Admin */
      case 'a':   g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip =
                              g.okRdWiki = g.okWrWiki = g.okNewWiki =
                              g.okApndWiki = g.okHistory = g.okClone = 
                              g.okNewTkt = g.okPassword = g.okRdAddr =
                              g.okTktFmt = g.okAttach = g.okApndTkt = 1;
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629











































































630
631
632
633
634
635
636
      /* case 'q': */
      case 'r':  rc = g.okRdTkt;     break;
      case 's':  rc = g.okSetup;     break;
      case 't':  rc = g.okTktFmt;    break;
      /* case 'u': READER    */
      /* case 'v': DEVELOPER */
      case 'w':  rc = g.okWrTkt;     break;
      /* case 'x': */
      /* case 'y': */
      case 'z':  rc = g.okZip;       break;
      default:   rc = 0;             break;
    }
  }
  return rc;
}












































































/*
** Call this routine when the credential check fails.  It causes
** a redirect to the "login" page.
*/
void login_needed(void){
  const char *zUrl = PD("REQUEST_URI", "index");







|







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
      /* case 'q': */
      case 'r':  rc = g.okRdTkt;     break;
      case 's':  rc = g.okSetup;     break;
      case 't':  rc = g.okTktFmt;    break;
      /* case 'u': READER    */
      /* case 'v': DEVELOPER */
      case 'w':  rc = g.okWrTkt;     break;
      case 'x':  rc = g.okPrivate;   break;
      /* case 'y': */
      case 'z':  rc = g.okZip;       break;
      default:   rc = 0;             break;
    }
  }
  return rc;
}

/*
** For every character in zCap between 'a' and 'z' set a byte in seen[].
*/
static void setCap(const char *zCap, char *seen){
  int c;
  if( zCap ){
    while( (c = *(zCap++))!=0 ){
      if( c>='a' && c<='z' ) seen[c-'a'] = 1;
    }
  }
}

/*
** Remove privileges such that previleges are restricted to the
** set given in the argument.
*/
void login_restrict_capabilities(const char *zAllowed){
  char zNew[30];
  char seen[26];
  int nNew = 0;
  int i;

  /* Compute the intersection of current settings with zAllowed[] and
  ** store the result in zNew[]
  */
  memset(seen, 0, sizeof(seen));
  setCap(zAllowed, seen);
  if( seen['v'-'a'] ){
    char *z = db_text(0, "SELECT cap FROM user WHERE login='developer'");
    setCap(z, seen);
    fossil_free(z);
  }
  if( seen['u'-'a'] ){
    char *z = db_text(0, "SELECT cap FROM user WHERE login='reader'");
    setCap(z, seen);
    fossil_free(z);
  }
  seen['u'-'a'] = 0;
  seen['v'-'a'] = 0;
  for(i=0; i<sizeof(seen); i++){
    if( seen[i] && login_settings[i] ) zNew[nNew++] = i+'a';
  }
  zNew[nNew] = 0;

  /* Turn off all capabilities */
  g.okSetup = 0;
  g.okAdmin = 0;
  g.okDelete = 0;
  g.okPassword = 0;
  g.okQuery = 0;
  g.okWrite = 0;
  g.okRead = 0;
  g.okHistory = 0;
  g.okClone = 0;
  g.okRdWiki = 0;
  g.okNewWiki = 0;
  g.okApndWiki = 0;
  g.okWrWiki = 0;
  g.okRdTkt = 0;
  g.okNewTkt = 0;
  g.okApndTkt = 0;
  g.okWrTkt = 0;
  g.okAttach = 0;
  g.okTktFmt = 0;
  g.okRdAddr = 0;
  g.okZip = 0;
  g.okPrivate = 0;
  memset(login_settings, 0, sizeof(login_settings));

  /* Set the reduced capabilities */
  login_set_capabilities(zNew);
  login_anon_once = 1;
  login_set_anon_nobody_capabilities();
}

/*
** Call this routine when the credential check fails.  It causes
** a redirect to the "login" page.
*/
void login_needed(void){
  const char *zUrl = PD("REQUEST_URI", "index");
Changes to src/main.c.
981
982
983
984
985
986
987
988


989
990
991
992
993


994







995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
      zPath[i] = 0;
      g.zExtra = &zPath[i+1];

      /* Look for sub-repositories.  A sub-repository is another repository
      ** that accepts the login credentials of the current repository.  A
      ** subrepository is identified by a CONFIG table entry "subrepo:NAME"
      ** where NAME is the first component of the path.  The value of the
      ** the CONFIG entries is the name of the repository.


      */
      zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'",
                         g.zPath);
      if( zAltRepo ){
        int nHost;


        login_check_credentials();







        if( zAltRepo[0]!='/' ){
          zAltRepo = mprintf("%s/../%z", g.zRepositoryName, zAltRepo);
          file_simplify_name(zAltRepo, -1);
        }
        db_close(1);
        db_open_repository(zAltRepo);
        fossil_free(zAltRepo);
        zPath += i;
        nHost = g.zTop - g.zBaseURL;
        g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
        g.zTop = g.zBaseURL + nHost;
        continue;
      }
    }else{







|
>
>





>
>

>
>
>
>
>
>
>

|




|







981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
      zPath[i] = 0;
      g.zExtra = &zPath[i+1];

      /* Look for sub-repositories.  A sub-repository is another repository
      ** that accepts the login credentials of the current repository.  A
      ** subrepository is identified by a CONFIG table entry "subrepo:NAME"
      ** where NAME is the first component of the path.  The value of the
      ** the CONFIG entries is the string "CAP:FILENAME" where CAP is the
      ** maximum capability string and FILENAME is the new repository 
      ** filename. 
      */
      zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'",
                         g.zPath);
      if( zAltRepo ){
        int nHost;
        int jj;
        char *zInheritCap = zAltRepo;
        login_check_credentials();
        for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){}
        if( zAltRepo[jj]==':' ){
          zAltRepo[jj] = 0;
          zAltRepo += jj+1;
        }else{
          zInheritCap = "";
        }
        if( zAltRepo[0]!='/' ){
          zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
          file_simplify_name(zAltRepo, -1);
        }
        db_close(1);
        db_open_repository(zAltRepo);
        login_restrict_capabilities(zInheritCap);
        zPath += i;
        nHost = g.zTop - g.zBaseURL;
        g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
        g.zTop = g.zBaseURL + nHost;
        continue;
      }
    }else{