Fossil SCM
Fixed the --chroot flag to "fossil server" and "fossil http" to allow it to work in conjunction with the single-repository case. Before, it blindly assumed --repolist mode.
Commit
6f92ad99d992f61c0dee9b3f67422f877ae5917e1fac601714a16e172d4d37ac
Parent
73c95307c94c423…
1 file changed
+24
-15
+24
-15
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -1471,21 +1471,24 @@ | ||
| 1471 | 1471 | /* |
| 1472 | 1472 | ** If running as root, chroot to the directory containing the |
| 1473 | 1473 | ** repository zRepo and then drop root privileges. Return the |
| 1474 | 1474 | ** new repository name. |
| 1475 | 1475 | ** |
| 1476 | -** zRepo might be a directory itself. In that case chroot into | |
| 1477 | -** the directory zRepo. | |
| 1476 | +** zRepo can be a directory. If so and if the repo name was saved | |
| 1477 | +** to g.zRepositoryName before we were called, we canonicalize the | |
| 1478 | +** two paths and check that one is the prefix of the other, else you | |
| 1479 | +** won't be able to open the repo inside the jail. If it all works | |
| 1480 | +** out, we return the "jailed" version of the repo name. | |
| 1478 | 1481 | ** |
| 1479 | 1482 | ** Assume the user-id and group-id of the repository, or if zRepo |
| 1480 | 1483 | ** is a directory, of that directory. |
| 1481 | 1484 | ** |
| 1482 | 1485 | ** The noJail flag means that the chroot jail is not entered. But |
| 1483 | 1486 | ** privileges are still lowered to that of the user-id and group-id |
| 1484 | 1487 | ** of the repository file. |
| 1485 | 1488 | */ |
| 1486 | -char *enter_chroot_jail(char *zRepo, int noJail){ | |
| 1489 | +static char *enter_chroot_jail(const char *zRepo, int noJail){ | |
| 1487 | 1490 | #if !defined(_WIN32) |
| 1488 | 1491 | if( getuid()==0 ){ |
| 1489 | 1492 | int i; |
| 1490 | 1493 | struct stat sStat; |
| 1491 | 1494 | Blob dir; |
| @@ -1500,11 +1503,23 @@ | ||
| 1500 | 1503 | if( file_isdir(zDir, ExtFILE)==1 ){ |
| 1501 | 1504 | if( file_chdir(zDir, 1) ){ |
| 1502 | 1505 | fossil_panic("unable to chroot into %s", zDir); |
| 1503 | 1506 | } |
| 1504 | 1507 | g.fJail = 1; |
| 1505 | - zRepo = "/"; | |
| 1508 | + if( g.zRepositoryName ){ | |
| 1509 | + size_t n = strlen(zDir); | |
| 1510 | + Blob repo; | |
| 1511 | + file_canonical_name(g.zRepositoryName, &repo, 0); | |
| 1512 | + zRepo = blob_str(&repo); | |
| 1513 | + if( strncmp(zRepo, zDir, n)!=0 ){ | |
| 1514 | + fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir); | |
| 1515 | + } | |
| 1516 | + zRepo += n; | |
| 1517 | + if( *zRepo == '\0' ) zRepo = "/"; | |
| 1518 | + }else { | |
| 1519 | + zRepo = "/"; | |
| 1520 | + } | |
| 1506 | 1521 | }else{ |
| 1507 | 1522 | for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} |
| 1508 | 1523 | if( zDir[i]!='/' ) fossil_fatal("bad repository name: %s", zRepo); |
| 1509 | 1524 | if( i>0 ){ |
| 1510 | 1525 | zDir[i] = 0; |
| @@ -1527,11 +1542,11 @@ | ||
| 1527 | 1542 | if( g.db==0 && file_isfile(zRepo, ExtFILE) ){ |
| 1528 | 1543 | db_open_repository(zRepo); |
| 1529 | 1544 | } |
| 1530 | 1545 | } |
| 1531 | 1546 | #endif |
| 1532 | - return zRepo; | |
| 1547 | + return (char*)zRepo; /* no longer const: always reassigned from blob_str() */ | |
| 1533 | 1548 | } |
| 1534 | 1549 | |
| 1535 | 1550 | /* |
| 1536 | 1551 | ** Called whenever a crash is encountered while processing a webpage. |
| 1537 | 1552 | */ |
| @@ -2814,15 +2829,12 @@ | ||
| 2814 | 2829 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2815 | 2830 | if( zIpAddr && zIpAddr[0] ){ |
| 2816 | 2831 | g.fSshClient |= CGI_SSH_CLIENT; |
| 2817 | 2832 | } |
| 2818 | 2833 | } |
| 2819 | - if( zChRoot ){ | |
| 2820 | - enter_chroot_jail((char*)zChRoot, noJail); | |
| 2821 | - }else{ | |
| 2822 | - g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); | |
| 2823 | - } | |
| 2834 | + g.zRepositoryName = enter_chroot_jail( | |
| 2835 | + zChRoot ? zChRoot : g.zRepositoryName, noJail); | |
| 2824 | 2836 | if( useSCGI ){ |
| 2825 | 2837 | cgi_handle_scgi_request(); |
| 2826 | 2838 | }else if( g.fSshClient & CGI_SSH_CLIENT ){ |
| 2827 | 2839 | ssh_request_loop(zIpAddr, glob_create(zFileGlob)); |
| 2828 | 2840 | }else{ |
| @@ -3319,15 +3331,12 @@ | ||
| 3319 | 3331 | g.cgiOutput = 1; |
| 3320 | 3332 | find_server_repository(2, 0); |
| 3321 | 3333 | if( fossil_strcmp(g.zRepositoryName,"/")==0 ){ |
| 3322 | 3334 | allowRepoList = 1; |
| 3323 | 3335 | }else{ |
| 3324 | - if( zChRoot ){ | |
| 3325 | - enter_chroot_jail((char*)zChRoot, noJail); | |
| 3326 | - }else{ | |
| 3327 | - g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); | |
| 3328 | - } | |
| 3336 | + g.zRepositoryName = enter_chroot_jail( | |
| 3337 | + zChRoot ? zChRoot : g.zRepositoryName, noJail); | |
| 3329 | 3338 | } |
| 3330 | 3339 | if( flags & HTTP_SERVER_SCGI ){ |
| 3331 | 3340 | cgi_handle_scgi_request(); |
| 3332 | 3341 | }else if( g.httpUseSSL ){ |
| 3333 | 3342 | #if FOSSIL_ENABLE_SSL |
| 3334 | 3343 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -1471,21 +1471,24 @@ | |
| 1471 | /* |
| 1472 | ** If running as root, chroot to the directory containing the |
| 1473 | ** repository zRepo and then drop root privileges. Return the |
| 1474 | ** new repository name. |
| 1475 | ** |
| 1476 | ** zRepo might be a directory itself. In that case chroot into |
| 1477 | ** the directory zRepo. |
| 1478 | ** |
| 1479 | ** Assume the user-id and group-id of the repository, or if zRepo |
| 1480 | ** is a directory, of that directory. |
| 1481 | ** |
| 1482 | ** The noJail flag means that the chroot jail is not entered. But |
| 1483 | ** privileges are still lowered to that of the user-id and group-id |
| 1484 | ** of the repository file. |
| 1485 | */ |
| 1486 | char *enter_chroot_jail(char *zRepo, int noJail){ |
| 1487 | #if !defined(_WIN32) |
| 1488 | if( getuid()==0 ){ |
| 1489 | int i; |
| 1490 | struct stat sStat; |
| 1491 | Blob dir; |
| @@ -1500,11 +1503,23 @@ | |
| 1500 | if( file_isdir(zDir, ExtFILE)==1 ){ |
| 1501 | if( file_chdir(zDir, 1) ){ |
| 1502 | fossil_panic("unable to chroot into %s", zDir); |
| 1503 | } |
| 1504 | g.fJail = 1; |
| 1505 | zRepo = "/"; |
| 1506 | }else{ |
| 1507 | for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} |
| 1508 | if( zDir[i]!='/' ) fossil_fatal("bad repository name: %s", zRepo); |
| 1509 | if( i>0 ){ |
| 1510 | zDir[i] = 0; |
| @@ -1527,11 +1542,11 @@ | |
| 1527 | if( g.db==0 && file_isfile(zRepo, ExtFILE) ){ |
| 1528 | db_open_repository(zRepo); |
| 1529 | } |
| 1530 | } |
| 1531 | #endif |
| 1532 | return zRepo; |
| 1533 | } |
| 1534 | |
| 1535 | /* |
| 1536 | ** Called whenever a crash is encountered while processing a webpage. |
| 1537 | */ |
| @@ -2814,15 +2829,12 @@ | |
| 2814 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2815 | if( zIpAddr && zIpAddr[0] ){ |
| 2816 | g.fSshClient |= CGI_SSH_CLIENT; |
| 2817 | } |
| 2818 | } |
| 2819 | if( zChRoot ){ |
| 2820 | enter_chroot_jail((char*)zChRoot, noJail); |
| 2821 | }else{ |
| 2822 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2823 | } |
| 2824 | if( useSCGI ){ |
| 2825 | cgi_handle_scgi_request(); |
| 2826 | }else if( g.fSshClient & CGI_SSH_CLIENT ){ |
| 2827 | ssh_request_loop(zIpAddr, glob_create(zFileGlob)); |
| 2828 | }else{ |
| @@ -3319,15 +3331,12 @@ | |
| 3319 | g.cgiOutput = 1; |
| 3320 | find_server_repository(2, 0); |
| 3321 | if( fossil_strcmp(g.zRepositoryName,"/")==0 ){ |
| 3322 | allowRepoList = 1; |
| 3323 | }else{ |
| 3324 | if( zChRoot ){ |
| 3325 | enter_chroot_jail((char*)zChRoot, noJail); |
| 3326 | }else{ |
| 3327 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 3328 | } |
| 3329 | } |
| 3330 | if( flags & HTTP_SERVER_SCGI ){ |
| 3331 | cgi_handle_scgi_request(); |
| 3332 | }else if( g.httpUseSSL ){ |
| 3333 | #if FOSSIL_ENABLE_SSL |
| 3334 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -1471,21 +1471,24 @@ | |
| 1471 | /* |
| 1472 | ** If running as root, chroot to the directory containing the |
| 1473 | ** repository zRepo and then drop root privileges. Return the |
| 1474 | ** new repository name. |
| 1475 | ** |
| 1476 | ** zRepo can be a directory. If so and if the repo name was saved |
| 1477 | ** to g.zRepositoryName before we were called, we canonicalize the |
| 1478 | ** two paths and check that one is the prefix of the other, else you |
| 1479 | ** won't be able to open the repo inside the jail. If it all works |
| 1480 | ** out, we return the "jailed" version of the repo name. |
| 1481 | ** |
| 1482 | ** Assume the user-id and group-id of the repository, or if zRepo |
| 1483 | ** is a directory, of that directory. |
| 1484 | ** |
| 1485 | ** The noJail flag means that the chroot jail is not entered. But |
| 1486 | ** privileges are still lowered to that of the user-id and group-id |
| 1487 | ** of the repository file. |
| 1488 | */ |
| 1489 | static char *enter_chroot_jail(const char *zRepo, int noJail){ |
| 1490 | #if !defined(_WIN32) |
| 1491 | if( getuid()==0 ){ |
| 1492 | int i; |
| 1493 | struct stat sStat; |
| 1494 | Blob dir; |
| @@ -1500,11 +1503,23 @@ | |
| 1503 | if( file_isdir(zDir, ExtFILE)==1 ){ |
| 1504 | if( file_chdir(zDir, 1) ){ |
| 1505 | fossil_panic("unable to chroot into %s", zDir); |
| 1506 | } |
| 1507 | g.fJail = 1; |
| 1508 | if( g.zRepositoryName ){ |
| 1509 | size_t n = strlen(zDir); |
| 1510 | Blob repo; |
| 1511 | file_canonical_name(g.zRepositoryName, &repo, 0); |
| 1512 | zRepo = blob_str(&repo); |
| 1513 | if( strncmp(zRepo, zDir, n)!=0 ){ |
| 1514 | fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir); |
| 1515 | } |
| 1516 | zRepo += n; |
| 1517 | if( *zRepo == '\0' ) zRepo = "/"; |
| 1518 | }else { |
| 1519 | zRepo = "/"; |
| 1520 | } |
| 1521 | }else{ |
| 1522 | for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} |
| 1523 | if( zDir[i]!='/' ) fossil_fatal("bad repository name: %s", zRepo); |
| 1524 | if( i>0 ){ |
| 1525 | zDir[i] = 0; |
| @@ -1527,11 +1542,11 @@ | |
| 1542 | if( g.db==0 && file_isfile(zRepo, ExtFILE) ){ |
| 1543 | db_open_repository(zRepo); |
| 1544 | } |
| 1545 | } |
| 1546 | #endif |
| 1547 | return (char*)zRepo; /* no longer const: always reassigned from blob_str() */ |
| 1548 | } |
| 1549 | |
| 1550 | /* |
| 1551 | ** Called whenever a crash is encountered while processing a webpage. |
| 1552 | */ |
| @@ -2814,15 +2829,12 @@ | |
| 2829 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2830 | if( zIpAddr && zIpAddr[0] ){ |
| 2831 | g.fSshClient |= CGI_SSH_CLIENT; |
| 2832 | } |
| 2833 | } |
| 2834 | g.zRepositoryName = enter_chroot_jail( |
| 2835 | zChRoot ? zChRoot : g.zRepositoryName, noJail); |
| 2836 | if( useSCGI ){ |
| 2837 | cgi_handle_scgi_request(); |
| 2838 | }else if( g.fSshClient & CGI_SSH_CLIENT ){ |
| 2839 | ssh_request_loop(zIpAddr, glob_create(zFileGlob)); |
| 2840 | }else{ |
| @@ -3319,15 +3331,12 @@ | |
| 3331 | g.cgiOutput = 1; |
| 3332 | find_server_repository(2, 0); |
| 3333 | if( fossil_strcmp(g.zRepositoryName,"/")==0 ){ |
| 3334 | allowRepoList = 1; |
| 3335 | }else{ |
| 3336 | g.zRepositoryName = enter_chroot_jail( |
| 3337 | zChRoot ? zChRoot : g.zRepositoryName, noJail); |
| 3338 | } |
| 3339 | if( flags & HTTP_SERVER_SCGI ){ |
| 3340 | cgi_handle_scgi_request(); |
| 3341 | }else if( g.httpUseSSL ){ |
| 3342 | #if FOSSIL_ENABLE_SSL |
| 3343 |