Fossil SCM

Relax constraints on PATHINFO names such that the "fossil ui /" command can be used if some repositories have non-ASCII filenames. Response to [forum:/forumpost/ec3ab5b1f5|forum post ec3ab5b1f5].

drh 2024-05-18 14:12 trunk
Commit 362a7b7c9de817d1f8079b1bfccac55f336f30a54a57c4d34b26962f31a0c7bc
1 file changed +29 -10
+29 -10
--- src/main.c
+++ src/main.c
@@ -1702,10 +1702,17 @@
17021702
17031703
g.zPhase = "process_one_web_page";
17041704
#if !defined(_WIN32)
17051705
signal(SIGSEGV, sigsegv_handler);
17061706
#endif
1707
+
1708
+ /* Decode %HH escapes in PATHINFO */
1709
+ if( strchr(zPathInfo,'%') ){
1710
+ char *z = fossil_strdup(zPathInfo);
1711
+ dehttpize(z);
1712
+ zPathInfo = z;
1713
+ }
17071714
17081715
/* Handle universal query parameters */
17091716
if( PB("utc") ){
17101717
g.fTimeFormat = 1;
17111718
}else if( PB("localtime") ){
@@ -1757,32 +1764,44 @@
17571764
@ <!-- Looking for repository named "%h(zRepo)" -->
17581765
fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
17591766
}
17601767
17611768
1762
- /* For safety -- to prevent an attacker from accessing arbitrary disk
1763
- ** files by sending a maliciously crafted request URI to a public
1764
- ** server -- make sure the repository basename contains no
1765
- ** characters other than alphanumerics, "/", "_", "-", and ".", and
1766
- ** that "-" never occurs immediately after a "/" and that "." is always
1767
- ** surrounded by two alphanumerics. Any character that does not
1768
- ** satisfy these constraints is converted into "_".
1769
- */
1769
+ /* Restrictions on the URI for security:
1770
+ **
1771
+ ** 1. Reject characters that are not ASCII alphanumerics,
1772
+ ** "-", "_", ".", "/", or unicode (above ASCII).
1773
+ ** In other words: No ASCII punctuation or control characters
1774
+ ** other than "-", "_", "." and "/".
1775
+ ** 2. Exception to rule 1: Allow /X:/ where X is any ASCII
1776
+ ** alphabetic character at the beginning of the name on windows.
1777
+ ** 3. "-" may not occur immediately after "/"
1778
+ ** 4. "." may not be adjacent to another "." or to "/"
1779
+ **
1780
+ ** Any character does not satisfy these constraints a Not Found
1781
+ ** error is returned.
1782
+ */
17701783
szFile = 0;
17711784
for(j=nBase+1, k=0; zRepo[j] && k<i-1; j++, k++){
17721785
char c = zRepo[j];
1773
- if( fossil_isalnum(c) ) continue;
1786
+ if( c>='a' && c<='z' ) continue;
1787
+ if( c>='A' && c<='Z' ) continue;
1788
+ if( c>='0' && c<='9' ) continue;
1789
+ if( (c&0x80)==0x80 ) continue;
17741790
#if defined(_WIN32) || defined(__CYGWIN__)
17751791
/* Allow names to begin with "/X:/" on windows */
17761792
if( c==':' && j==2 && sqlite3_strglob("/[a-zA-Z]:/*", zRepo)==0 ){
17771793
continue;
17781794
}
17791795
#endif
17801796
if( c=='/' ) continue;
17811797
if( c=='_' ) continue;
17821798
if( c=='-' && zRepo[j-1]!='/' ) continue;
1783
- if( c=='.' && fossil_isalnum(zRepo[j-1]) && fossil_isalnum(zRepo[j+1])){
1799
+ if( c=='.'
1800
+ && zRepo[j-1]!='.' && zRepo[j-1]!='/'
1801
+ && zRepo[j+1]!='.' && zRepo[j+1]!='/'
1802
+ ){
17841803
continue;
17851804
}
17861805
if( c=='.' && g.fAllowACME && j==(int)nBase+1
17871806
&& strncmp(&zRepo[j-1],"/.well-known/",12)==0
17881807
){
17891808
--- src/main.c
+++ src/main.c
@@ -1702,10 +1702,17 @@
1702
1703 g.zPhase = "process_one_web_page";
1704 #if !defined(_WIN32)
1705 signal(SIGSEGV, sigsegv_handler);
1706 #endif
 
 
 
 
 
 
 
1707
1708 /* Handle universal query parameters */
1709 if( PB("utc") ){
1710 g.fTimeFormat = 1;
1711 }else if( PB("localtime") ){
@@ -1757,32 +1764,44 @@
1757 @ <!-- Looking for repository named "%h(zRepo)" -->
1758 fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
1759 }
1760
1761
1762 /* For safety -- to prevent an attacker from accessing arbitrary disk
1763 ** files by sending a maliciously crafted request URI to a public
1764 ** server -- make sure the repository basename contains no
1765 ** characters other than alphanumerics, "/", "_", "-", and ".", and
1766 ** that "-" never occurs immediately after a "/" and that "." is always
1767 ** surrounded by two alphanumerics. Any character that does not
1768 ** satisfy these constraints is converted into "_".
1769 */
 
 
 
 
 
 
1770 szFile = 0;
1771 for(j=nBase+1, k=0; zRepo[j] && k<i-1; j++, k++){
1772 char c = zRepo[j];
1773 if( fossil_isalnum(c) ) continue;
 
 
 
1774 #if defined(_WIN32) || defined(__CYGWIN__)
1775 /* Allow names to begin with "/X:/" on windows */
1776 if( c==':' && j==2 && sqlite3_strglob("/[a-zA-Z]:/*", zRepo)==0 ){
1777 continue;
1778 }
1779 #endif
1780 if( c=='/' ) continue;
1781 if( c=='_' ) continue;
1782 if( c=='-' && zRepo[j-1]!='/' ) continue;
1783 if( c=='.' && fossil_isalnum(zRepo[j-1]) && fossil_isalnum(zRepo[j+1])){
 
 
 
1784 continue;
1785 }
1786 if( c=='.' && g.fAllowACME && j==(int)nBase+1
1787 && strncmp(&zRepo[j-1],"/.well-known/",12)==0
1788 ){
1789
--- src/main.c
+++ src/main.c
@@ -1702,10 +1702,17 @@
1702
1703 g.zPhase = "process_one_web_page";
1704 #if !defined(_WIN32)
1705 signal(SIGSEGV, sigsegv_handler);
1706 #endif
1707
1708 /* Decode %HH escapes in PATHINFO */
1709 if( strchr(zPathInfo,'%') ){
1710 char *z = fossil_strdup(zPathInfo);
1711 dehttpize(z);
1712 zPathInfo = z;
1713 }
1714
1715 /* Handle universal query parameters */
1716 if( PB("utc") ){
1717 g.fTimeFormat = 1;
1718 }else if( PB("localtime") ){
@@ -1757,32 +1764,44 @@
1764 @ <!-- Looking for repository named "%h(zRepo)" -->
1765 fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
1766 }
1767
1768
1769 /* Restrictions on the URI for security:
1770 **
1771 ** 1. Reject characters that are not ASCII alphanumerics,
1772 ** "-", "_", ".", "/", or unicode (above ASCII).
1773 ** In other words: No ASCII punctuation or control characters
1774 ** other than "-", "_", "." and "/".
1775 ** 2. Exception to rule 1: Allow /X:/ where X is any ASCII
1776 ** alphabetic character at the beginning of the name on windows.
1777 ** 3. "-" may not occur immediately after "/"
1778 ** 4. "." may not be adjacent to another "." or to "/"
1779 **
1780 ** Any character does not satisfy these constraints a Not Found
1781 ** error is returned.
1782 */
1783 szFile = 0;
1784 for(j=nBase+1, k=0; zRepo[j] && k<i-1; j++, k++){
1785 char c = zRepo[j];
1786 if( c>='a' && c<='z' ) continue;
1787 if( c>='A' && c<='Z' ) continue;
1788 if( c>='0' && c<='9' ) continue;
1789 if( (c&0x80)==0x80 ) continue;
1790 #if defined(_WIN32) || defined(__CYGWIN__)
1791 /* Allow names to begin with "/X:/" on windows */
1792 if( c==':' && j==2 && sqlite3_strglob("/[a-zA-Z]:/*", zRepo)==0 ){
1793 continue;
1794 }
1795 #endif
1796 if( c=='/' ) continue;
1797 if( c=='_' ) continue;
1798 if( c=='-' && zRepo[j-1]!='/' ) continue;
1799 if( c=='.'
1800 && zRepo[j-1]!='.' && zRepo[j-1]!='/'
1801 && zRepo[j+1]!='.' && zRepo[j+1]!='/'
1802 ){
1803 continue;
1804 }
1805 if( c=='.' && g.fAllowACME && j==(int)nBase+1
1806 && strncmp(&zRepo[j-1],"/.well-known/",12)==0
1807 ){
1808

Keyboard Shortcuts

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