Fossil SCM

Query and post parameters may never begin with an upper-case letter. To allow that is a huge security hole.

drh 2019-08-27 10:40 noJsonCgiFlag
Commit 72c721eacf9401f3e6e84be1994debfe5084948d5fa65a681b2d281484cdf4d1
+4 -19
--- src/cgi.c
+++ src/cgi.c
@@ -562,25 +562,10 @@
562562
*/
563563
void cgi_setenv(const char *zName, const char *zValue){
564564
cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0);
565565
}
566566
567
-
568
-/*
569
-** Returns non-zero if the specified character is lowercase -OR-
570
-** the specified character is uppercase and the CGI subsystem has
571
-** been configured to allow uppercase parameter names.
572
-*/
573
-int cgi_char_allowed(char c){
574
- if( fossil_islower(c) ){
575
- return 1; /* lowercase letter, always OK */
576
- }else if( fossil_isupper(c) && g.cgiUpperParamsOk ){
577
- return 1; /* uppercase letter, OK if allowed explicitly */
578
- }
579
- return 0; /* something else, never OK */
580
-}
581
-
582567
/*
583568
** Add a list of query parameters or cookies to the parameter set.
584569
**
585570
** Each parameter is of the form NAME=VALUE. Both the NAME and the
586571
** VALUE may be url-encoded ("+" for space, "%HH" for other special
@@ -629,11 +614,11 @@
629614
dehttpize(zValue);
630615
}else{
631616
if( *z ){ *z++ = 0; }
632617
zValue = "";
633618
}
634
- if( cgi_char_allowed(zName[0]) && fossil_no_strange_characters(zName+1) ){
619
+ if( fossil_islower(zName[0]) && fossil_no_strange_characters(zName+1) ){
635620
cgi_set_parameter_nocopy(zName, zValue, isQP);
636621
}
637622
#ifdef FOSSIL_ENABLE_JSON
638623
json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) );
639624
#endif /* FOSSIL_ENABLE_JSON */
@@ -773,11 +758,11 @@
773758
if( zBoundry==0 ) return;
774759
while( (zLine = get_line_from_string(&z, &len))!=0 ){
775760
if( zLine[0]==0 ){
776761
int nContent = 0;
777762
zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
778
- if( zName && zValue && cgi_char_allowed(zName[0]) ){
763
+ if( zName && zValue && fossil_islower(zName[0]) ){
779764
cgi_set_parameter_nocopy(zName, zValue, 1);
780765
if( showBytes ){
781766
cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
782767
mprintf("%d",nContent), 1);
783768
}
@@ -793,17 +778,17 @@
793778
i++;
794779
}else if( c=='n' && sqlite3_strnicmp(azArg[i],"name=",n)==0 ){
795780
zName = azArg[++i];
796781
}else if( c=='f' && sqlite3_strnicmp(azArg[i],"filename=",n)==0 ){
797782
char *z = azArg[++i];
798
- if( zName && z && cgi_char_allowed(zName[0]) ){
783
+ if( zName && z && fossil_islower(zName[0]) ){
799784
cgi_set_parameter_nocopy(mprintf("%s:filename",zName), z, 1);
800785
}
801786
showBytes = 1;
802787
}else if( c=='c' && sqlite3_strnicmp(azArg[i],"content-type:",n)==0 ){
803788
char *z = azArg[++i];
804
- if( zName && z && cgi_char_allowed(zName[0]) ){
789
+ if( zName && z && fossil_islower(zName[0]) ){
805790
cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1);
806791
}
807792
}
808793
}
809794
}
810795
--- src/cgi.c
+++ src/cgi.c
@@ -562,25 +562,10 @@
562 */
563 void cgi_setenv(const char *zName, const char *zValue){
564 cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0);
565 }
566
567
568 /*
569 ** Returns non-zero if the specified character is lowercase -OR-
570 ** the specified character is uppercase and the CGI subsystem has
571 ** been configured to allow uppercase parameter names.
572 */
573 int cgi_char_allowed(char c){
574 if( fossil_islower(c) ){
575 return 1; /* lowercase letter, always OK */
576 }else if( fossil_isupper(c) && g.cgiUpperParamsOk ){
577 return 1; /* uppercase letter, OK if allowed explicitly */
578 }
579 return 0; /* something else, never OK */
580 }
581
582 /*
583 ** Add a list of query parameters or cookies to the parameter set.
584 **
585 ** Each parameter is of the form NAME=VALUE. Both the NAME and the
586 ** VALUE may be url-encoded ("+" for space, "%HH" for other special
@@ -629,11 +614,11 @@
629 dehttpize(zValue);
630 }else{
631 if( *z ){ *z++ = 0; }
632 zValue = "";
633 }
634 if( cgi_char_allowed(zName[0]) && fossil_no_strange_characters(zName+1) ){
635 cgi_set_parameter_nocopy(zName, zValue, isQP);
636 }
637 #ifdef FOSSIL_ENABLE_JSON
638 json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) );
639 #endif /* FOSSIL_ENABLE_JSON */
@@ -773,11 +758,11 @@
773 if( zBoundry==0 ) return;
774 while( (zLine = get_line_from_string(&z, &len))!=0 ){
775 if( zLine[0]==0 ){
776 int nContent = 0;
777 zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
778 if( zName && zValue && cgi_char_allowed(zName[0]) ){
779 cgi_set_parameter_nocopy(zName, zValue, 1);
780 if( showBytes ){
781 cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
782 mprintf("%d",nContent), 1);
783 }
@@ -793,17 +778,17 @@
793 i++;
794 }else if( c=='n' && sqlite3_strnicmp(azArg[i],"name=",n)==0 ){
795 zName = azArg[++i];
796 }else if( c=='f' && sqlite3_strnicmp(azArg[i],"filename=",n)==0 ){
797 char *z = azArg[++i];
798 if( zName && z && cgi_char_allowed(zName[0]) ){
799 cgi_set_parameter_nocopy(mprintf("%s:filename",zName), z, 1);
800 }
801 showBytes = 1;
802 }else if( c=='c' && sqlite3_strnicmp(azArg[i],"content-type:",n)==0 ){
803 char *z = azArg[++i];
804 if( zName && z && cgi_char_allowed(zName[0]) ){
805 cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1);
806 }
807 }
808 }
809 }
810
--- src/cgi.c
+++ src/cgi.c
@@ -562,25 +562,10 @@
562 */
563 void cgi_setenv(const char *zName, const char *zValue){
564 cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0);
565 }
566
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567 /*
568 ** Add a list of query parameters or cookies to the parameter set.
569 **
570 ** Each parameter is of the form NAME=VALUE. Both the NAME and the
571 ** VALUE may be url-encoded ("+" for space, "%HH" for other special
@@ -629,11 +614,11 @@
614 dehttpize(zValue);
615 }else{
616 if( *z ){ *z++ = 0; }
617 zValue = "";
618 }
619 if( fossil_islower(zName[0]) && fossil_no_strange_characters(zName+1) ){
620 cgi_set_parameter_nocopy(zName, zValue, isQP);
621 }
622 #ifdef FOSSIL_ENABLE_JSON
623 json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) );
624 #endif /* FOSSIL_ENABLE_JSON */
@@ -773,11 +758,11 @@
758 if( zBoundry==0 ) return;
759 while( (zLine = get_line_from_string(&z, &len))!=0 ){
760 if( zLine[0]==0 ){
761 int nContent = 0;
762 zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
763 if( zName && zValue && fossil_islower(zName[0]) ){
764 cgi_set_parameter_nocopy(zName, zValue, 1);
765 if( showBytes ){
766 cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
767 mprintf("%d",nContent), 1);
768 }
@@ -793,17 +778,17 @@
778 i++;
779 }else if( c=='n' && sqlite3_strnicmp(azArg[i],"name=",n)==0 ){
780 zName = azArg[++i];
781 }else if( c=='f' && sqlite3_strnicmp(azArg[i],"filename=",n)==0 ){
782 char *z = azArg[++i];
783 if( zName && z && fossil_islower(zName[0]) ){
784 cgi_set_parameter_nocopy(mprintf("%s:filename",zName), z, 1);
785 }
786 showBytes = 1;
787 }else if( c=='c' && sqlite3_strnicmp(azArg[i],"content-type:",n)==0 ){
788 char *z = azArg[++i];
789 if( zName && z && fossil_islower(zName[0]) ){
790 cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1);
791 }
792 }
793 }
794 }
795
+1 -1
--- src/dispatch.c
+++ src/dispatch.c
@@ -194,11 +194,11 @@
194194
zName = "";
195195
}else{
196196
if( *z ){ *z++ = 0; }
197197
zValue = "";
198198
}
199
- if( cgi_char_allowed(zName[0]) ){
199
+ if( fossil_islower(zName[0]) ){
200200
cgi_replace_query_parameter(zName, zValue);
201201
}
202202
}
203203
return 0;
204204
}
205205
--- src/dispatch.c
+++ src/dispatch.c
@@ -194,11 +194,11 @@
194 zName = "";
195 }else{
196 if( *z ){ *z++ = 0; }
197 zValue = "";
198 }
199 if( cgi_char_allowed(zName[0]) ){
200 cgi_replace_query_parameter(zName, zValue);
201 }
202 }
203 return 0;
204 }
205
--- src/dispatch.c
+++ src/dispatch.c
@@ -194,11 +194,11 @@
194 zName = "";
195 }else{
196 if( *z ){ *z++ = 0; }
197 zValue = "";
198 }
199 if( fossil_islower(zName[0]) ){
200 cgi_replace_query_parameter(zName, zValue);
201 }
202 }
203 return 0;
204 }
205
-10
--- src/main.c
+++ src/main.c
@@ -211,11 +211,10 @@
211211
Blob httpHeader; /* Complete text of the HTTP request header */
212212
UrlData url; /* Information about current URL */
213213
const char *zLogin; /* Login name. NULL or "" if not logged in. */
214214
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
215215
** SSL client identity */
216
- int cgiUpperParamsOk; /* Allow CGI parameters to start with uppercase */
217216
int useLocalauth; /* No login required if from 127.0.0.1 */
218217
int noPswd; /* Logged in without password (on 127.0.0.1) */
219218
int userUid; /* Integer user id */
220219
int isHuman; /* True if access by a human, not a spider or bot */
221220
int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
@@ -731,11 +730,10 @@
731730
fossil_exit(1);
732731
}else{
733732
const char *zChdir = find_option("chdir",0,1);
734733
g.isHTTP = 0;
735734
g.rcvid = 0;
736
- g.cgiUpperParamsOk = find_option("cgiupperok", 0, 0)!=0;
737735
g.fQuiet = find_option("quiet", 0, 0)!=0;
738736
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
739737
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
740738
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
741739
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -2014,18 +2012,10 @@
20142012
fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
20152013
blob_read_from_file(&config, zFile, ExtFILE);
20162014
while( blob_line(&config, &line) ){
20172015
if( !blob_token(&line, &key) ) continue;
20182016
if( blob_buffer(&key)[0]=='#' ) continue;
2019
- if( blob_eq(&key, "uppercase_params") ){
2020
- /* uppercase_params
2021
- **
2022
- ** Allow CGI parameters to start with an uppercase letter.
2023
- */
2024
- g.cgiUpperParamsOk = 1;
2025
- continue;
2026
- }
20272017
if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
20282018
/* repository: FILENAME
20292019
**
20302020
** The name of the Fossil repository to be served via CGI. Most
20312021
** fossil CGI scripts have a single non-comment line that contains
20322022
--- src/main.c
+++ src/main.c
@@ -211,11 +211,10 @@
211 Blob httpHeader; /* Complete text of the HTTP request header */
212 UrlData url; /* Information about current URL */
213 const char *zLogin; /* Login name. NULL or "" if not logged in. */
214 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
215 ** SSL client identity */
216 int cgiUpperParamsOk; /* Allow CGI parameters to start with uppercase */
217 int useLocalauth; /* No login required if from 127.0.0.1 */
218 int noPswd; /* Logged in without password (on 127.0.0.1) */
219 int userUid; /* Integer user id */
220 int isHuman; /* True if access by a human, not a spider or bot */
221 int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
@@ -731,11 +730,10 @@
731 fossil_exit(1);
732 }else{
733 const char *zChdir = find_option("chdir",0,1);
734 g.isHTTP = 0;
735 g.rcvid = 0;
736 g.cgiUpperParamsOk = find_option("cgiupperok", 0, 0)!=0;
737 g.fQuiet = find_option("quiet", 0, 0)!=0;
738 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
739 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
740 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
741 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -2014,18 +2012,10 @@
2014 fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
2015 blob_read_from_file(&config, zFile, ExtFILE);
2016 while( blob_line(&config, &line) ){
2017 if( !blob_token(&line, &key) ) continue;
2018 if( blob_buffer(&key)[0]=='#' ) continue;
2019 if( blob_eq(&key, "uppercase_params") ){
2020 /* uppercase_params
2021 **
2022 ** Allow CGI parameters to start with an uppercase letter.
2023 */
2024 g.cgiUpperParamsOk = 1;
2025 continue;
2026 }
2027 if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
2028 /* repository: FILENAME
2029 **
2030 ** The name of the Fossil repository to be served via CGI. Most
2031 ** fossil CGI scripts have a single non-comment line that contains
2032
--- src/main.c
+++ src/main.c
@@ -211,11 +211,10 @@
211 Blob httpHeader; /* Complete text of the HTTP request header */
212 UrlData url; /* Information about current URL */
213 const char *zLogin; /* Login name. NULL or "" if not logged in. */
214 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
215 ** SSL client identity */
 
216 int useLocalauth; /* No login required if from 127.0.0.1 */
217 int noPswd; /* Logged in without password (on 127.0.0.1) */
218 int userUid; /* Integer user id */
219 int isHuman; /* True if access by a human, not a spider or bot */
220 int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
@@ -731,11 +730,10 @@
730 fossil_exit(1);
731 }else{
732 const char *zChdir = find_option("chdir",0,1);
733 g.isHTTP = 0;
734 g.rcvid = 0;
 
735 g.fQuiet = find_option("quiet", 0, 0)!=0;
736 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
737 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
738 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
739 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -2014,18 +2012,10 @@
2012 fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
2013 blob_read_from_file(&config, zFile, ExtFILE);
2014 while( blob_line(&config, &line) ){
2015 if( !blob_token(&line, &key) ) continue;
2016 if( blob_buffer(&key)[0]=='#' ) continue;
 
 
 
 
 
 
 
 
2017 if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
2018 /* repository: FILENAME
2019 **
2020 ** The name of the Fossil repository to be served via CGI. Most
2021 ** fossil CGI scripts have a single non-comment line that contains
2022
--- src/style.c
+++ src/style.c
@@ -1198,11 +1198,10 @@
11981198
@ g.zTop = %h(g.zTop)<br />
11991199
@ g.zPath = %h(g.zPath)<br />
12001200
@ g.userUid = %d(g.userUid)<br />
12011201
@ g.zLogin = %h(g.zLogin)<br />
12021202
@ g.isHuman = %d(g.isHuman)<br />
1203
- @ g.cgiUpperParamsOk = %d(g.cgiUpperParamsOk)<br />
12041203
if( g.nRequest ){
12051204
@ g.nRequest = %d(g.nRequest)<br />
12061205
}
12071206
if( g.nPendingRequest>1 ){
12081207
@ g.nPendingRequest = %d(g.nPendingRequest)<br />
12091208
--- src/style.c
+++ src/style.c
@@ -1198,11 +1198,10 @@
1198 @ g.zTop = %h(g.zTop)<br />
1199 @ g.zPath = %h(g.zPath)<br />
1200 @ g.userUid = %d(g.userUid)<br />
1201 @ g.zLogin = %h(g.zLogin)<br />
1202 @ g.isHuman = %d(g.isHuman)<br />
1203 @ g.cgiUpperParamsOk = %d(g.cgiUpperParamsOk)<br />
1204 if( g.nRequest ){
1205 @ g.nRequest = %d(g.nRequest)<br />
1206 }
1207 if( g.nPendingRequest>1 ){
1208 @ g.nPendingRequest = %d(g.nPendingRequest)<br />
1209
--- src/style.c
+++ src/style.c
@@ -1198,11 +1198,10 @@
1198 @ g.zTop = %h(g.zTop)<br />
1199 @ g.zPath = %h(g.zPath)<br />
1200 @ g.userUid = %d(g.userUid)<br />
1201 @ g.zLogin = %h(g.zLogin)<br />
1202 @ g.isHuman = %d(g.isHuman)<br />
 
1203 if( g.nRequest ){
1204 @ g.nRequest = %d(g.nRequest)<br />
1205 }
1206 if( g.nPendingRequest>1 ){
1207 @ g.nPendingRequest = %d(g.nPendingRequest)<br />
1208

Keyboard Shortcuts

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