Index: src/login.c ================================================================== --- src/login.c +++ src/login.c @@ -500,27 +500,31 @@ /* Set the capabilities */ login_set_capabilities(zCap); login_set_anon_nobody_capabilities(); } +/* +** Memory of settings +*/ +static int login_anon_once = 1; + /* ** 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 ){ + 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); } - once = 0; + login_anon_once = 0; } } /* ** Set the global capability flags based on a capability string. @@ -617,18 +621,68 @@ 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 'x': rc = g.okPrivate; break; /* case 'y': */ case 'z': rc = g.okZip; break; default: rc = 0; break; } } return rc; } + +/* +** Change the login to zUser. +*/ +void login_as_user(const char *zUser){ + char *zCap = ""; /* New capabilities */ + + /* Turn off all capabilities from prior logins */ + 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; + + /* Set the global variables recording the userid and login. The + ** "nobody" user is a special case in that g.zLogin==0. + */ + g.userUid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUser); + if( g.userUid==0 ){ + zUser = 0; + g.userUid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); + } + if( g.userUid ){ + zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", g.userUid); + } + if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0; + g.zLogin = fossil_strdup(zUser); + + /* Set the capabilities */ + login_set_capabilities(zCap); + 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. */ Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -968,19 +968,61 @@ fossil_redirect_home(); }else{ zPath = mprintf("%s", zPathInfo); } - /* Remove the leading "/" at the beginning of the path. + /* Make g.zPath point to the first element of the path. Make + ** g.zExtra point to everything past that point. */ - g.zPath = &zPath[1]; - for(i=1; zPath[i] && zPath[i]!='/'; i++){} - if( zPath[i]=='/' ){ - zPath[i] = 0; - g.zExtra = &zPath[i+1]; - }else{ - g.zExtra = 0; + while(1){ + char *zAltRepo = 0; + g.zPath = &zPath[1]; + for(i=1; zPath[i] && zPath[i]!='/'; i++){} + if( zPath[i]=='/' ){ + 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 "USER:FILENAME" where USER is the + ** USER name to log in as in the subrepository and FILENAME is the + ** repository filename. + */ + zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'", + g.zPath); + if( zAltRepo ){ + int nHost; + int jj; + char *zUser = zAltRepo; + login_check_credentials(); + for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){} + if( zAltRepo[jj]==':' ){ + zAltRepo[jj] = 0; + zAltRepo += jj+1; + }else{ + zUser = "nobody"; + } + if( zAltRepo[0]!='/' ){ + zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); + file_simplify_name(zAltRepo, -1); + } + db_close(1); + db_open_repository(zAltRepo); + login_as_user(zUser); + g.okPassword = 0; + zPath += i; + nHost = g.zTop - g.zBaseURL; + g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath); + g.zTop = g.zBaseURL + nHost; + continue; + } + }else{ + g.zExtra = 0; + } + break; } if( g.zExtra ){ /* CGI parameters get this treatment elsewhere, but places like getfile ** will use g.zExtra directly. */