Fossil SCM

Merge the CSRF-defense enhancements into trunk.

drh 2023-09-18 20:43 trunk merge
Commit 920ace17395fc150aaceedd7cbb416c693d06a4f134c54dacc5f762dc0a14b19
+7 -6
--- src/alerts.c
+++ src/alerts.c
@@ -1545,11 +1545,11 @@
15451545
}
15461546
style_set_current_feature("alerts");
15471547
alert_submenu_common();
15481548
needCaptcha = !login_is_individual();
15491549
if( P("submit")
1550
- && cgi_csrf_safe(1)
1550
+ && cgi_csrf_safe(2)
15511551
&& subscribe_error_check(&eErr,&zErr,needCaptcha)
15521552
){
15531553
/* A validated request for a new subscription has been received. */
15541554
char ssub[20];
15551555
const char *zEAddr = P("e");
@@ -1856,11 +1856,11 @@
18561856
db_commit_transaction();
18571857
cgi_redirect("subscribe");
18581858
/*NOTREACHED*/
18591859
}
18601860
alert_submenu_common();
1861
- if( P("submit")!=0 && cgi_csrf_safe(1) ){
1861
+ if( P("submit")!=0 && cgi_csrf_safe(2) ){
18621862
char newSsub[10];
18631863
int nsub = 0;
18641864
Blob update;
18651865
18661866
sdonotcall = PB("sdonotcall");
@@ -1918,11 +1918,11 @@
19181918
"UPDATE subscriber SET lastContact=now()/86400"
19191919
" WHERE subscriberId=%d", sid
19201920
);
19211921
db_protect_pop();
19221922
}
1923
- if( P("delete")!=0 && cgi_csrf_safe(1) ){
1923
+ if( P("delete")!=0 && cgi_csrf_safe(2) ){
19241924
if( !PB("dodelete") ){
19251925
eErr = 9;
19261926
zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
19271927
" unsubscribe");
19281928
}else{
@@ -2269,11 +2269,11 @@
22692269
22702270
style_set_current_feature("alerts");
22712271
22722272
zEAddr = PD("e","");
22732273
dx = atoi(PD("dx","0"));
2274
- bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(1);
2274
+ bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(2);
22752275
if( bSubmit ){
22762276
if( !captcha_is_correct(1) ){
22772277
eErr = 2;
22782278
zErr = mprintf("enter the security code shown below");
22792279
bSubmit = 0;
@@ -3300,11 +3300,11 @@
33003300
}
33013301
if( P("submit")!=0
33023302
&& P("subject")!=0
33033303
&& P("msg")!=0
33043304
&& P("from")!=0
3305
- && cgi_csrf_safe(1)
3305
+ && cgi_csrf_safe(2)
33063306
&& captcha_is_correct(0)
33073307
){
33083308
Blob hdr, body;
33093309
AlertSender *pSender = alert_sender_new(0,0);
33103310
blob_init(&hdr, 0, 0);
@@ -3477,11 +3477,11 @@
34773477
/* Visit the /announce/test1 page to see the CGI variables */
34783478
zAction = "announce/test1";
34793479
@ <p style='border: 1px solid black; padding: 1ex;'>
34803480
cgi_print_all(0, 0, 0);
34813481
@ </p>
3482
- }else if( P("submit")!=0 && cgi_csrf_safe(1) ){
3482
+ }else if( P("submit")!=0 && cgi_csrf_safe(2) ){
34833483
char *zErr = alert_send_announcement();
34843484
style_header("Announcement Sent");
34853485
if( zErr ){
34863486
@ <h1>Internal Error</h1>
34873487
@ <p>The following error was reported by the system:
@@ -3502,10 +3502,11 @@
35023502
return;
35033503
}
35043504
35053505
style_header("Send Announcement");
35063506
@ <form method="POST" action="%R/%s(zAction)">
3507
+ login_insert_csrf_secret();
35073508
@ <table class="subscribe">
35083509
if( g.perm.Admin ){
35093510
int aa = PB("aa");
35103511
int all = PB("all");
35113512
int aMod = PB("mods");
35123513
--- src/alerts.c
+++ src/alerts.c
@@ -1545,11 +1545,11 @@
1545 }
1546 style_set_current_feature("alerts");
1547 alert_submenu_common();
1548 needCaptcha = !login_is_individual();
1549 if( P("submit")
1550 && cgi_csrf_safe(1)
1551 && subscribe_error_check(&eErr,&zErr,needCaptcha)
1552 ){
1553 /* A validated request for a new subscription has been received. */
1554 char ssub[20];
1555 const char *zEAddr = P("e");
@@ -1856,11 +1856,11 @@
1856 db_commit_transaction();
1857 cgi_redirect("subscribe");
1858 /*NOTREACHED*/
1859 }
1860 alert_submenu_common();
1861 if( P("submit")!=0 && cgi_csrf_safe(1) ){
1862 char newSsub[10];
1863 int nsub = 0;
1864 Blob update;
1865
1866 sdonotcall = PB("sdonotcall");
@@ -1918,11 +1918,11 @@
1918 "UPDATE subscriber SET lastContact=now()/86400"
1919 " WHERE subscriberId=%d", sid
1920 );
1921 db_protect_pop();
1922 }
1923 if( P("delete")!=0 && cgi_csrf_safe(1) ){
1924 if( !PB("dodelete") ){
1925 eErr = 9;
1926 zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
1927 " unsubscribe");
1928 }else{
@@ -2269,11 +2269,11 @@
2269
2270 style_set_current_feature("alerts");
2271
2272 zEAddr = PD("e","");
2273 dx = atoi(PD("dx","0"));
2274 bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(1);
2275 if( bSubmit ){
2276 if( !captcha_is_correct(1) ){
2277 eErr = 2;
2278 zErr = mprintf("enter the security code shown below");
2279 bSubmit = 0;
@@ -3300,11 +3300,11 @@
3300 }
3301 if( P("submit")!=0
3302 && P("subject")!=0
3303 && P("msg")!=0
3304 && P("from")!=0
3305 && cgi_csrf_safe(1)
3306 && captcha_is_correct(0)
3307 ){
3308 Blob hdr, body;
3309 AlertSender *pSender = alert_sender_new(0,0);
3310 blob_init(&hdr, 0, 0);
@@ -3477,11 +3477,11 @@
3477 /* Visit the /announce/test1 page to see the CGI variables */
3478 zAction = "announce/test1";
3479 @ <p style='border: 1px solid black; padding: 1ex;'>
3480 cgi_print_all(0, 0, 0);
3481 @ </p>
3482 }else if( P("submit")!=0 && cgi_csrf_safe(1) ){
3483 char *zErr = alert_send_announcement();
3484 style_header("Announcement Sent");
3485 if( zErr ){
3486 @ <h1>Internal Error</h1>
3487 @ <p>The following error was reported by the system:
@@ -3502,10 +3502,11 @@
3502 return;
3503 }
3504
3505 style_header("Send Announcement");
3506 @ <form method="POST" action="%R/%s(zAction)">
 
3507 @ <table class="subscribe">
3508 if( g.perm.Admin ){
3509 int aa = PB("aa");
3510 int all = PB("all");
3511 int aMod = PB("mods");
3512
--- src/alerts.c
+++ src/alerts.c
@@ -1545,11 +1545,11 @@
1545 }
1546 style_set_current_feature("alerts");
1547 alert_submenu_common();
1548 needCaptcha = !login_is_individual();
1549 if( P("submit")
1550 && cgi_csrf_safe(2)
1551 && subscribe_error_check(&eErr,&zErr,needCaptcha)
1552 ){
1553 /* A validated request for a new subscription has been received. */
1554 char ssub[20];
1555 const char *zEAddr = P("e");
@@ -1856,11 +1856,11 @@
1856 db_commit_transaction();
1857 cgi_redirect("subscribe");
1858 /*NOTREACHED*/
1859 }
1860 alert_submenu_common();
1861 if( P("submit")!=0 && cgi_csrf_safe(2) ){
1862 char newSsub[10];
1863 int nsub = 0;
1864 Blob update;
1865
1866 sdonotcall = PB("sdonotcall");
@@ -1918,11 +1918,11 @@
1918 "UPDATE subscriber SET lastContact=now()/86400"
1919 " WHERE subscriberId=%d", sid
1920 );
1921 db_protect_pop();
1922 }
1923 if( P("delete")!=0 && cgi_csrf_safe(2) ){
1924 if( !PB("dodelete") ){
1925 eErr = 9;
1926 zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
1927 " unsubscribe");
1928 }else{
@@ -2269,11 +2269,11 @@
2269
2270 style_set_current_feature("alerts");
2271
2272 zEAddr = PD("e","");
2273 dx = atoi(PD("dx","0"));
2274 bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(2);
2275 if( bSubmit ){
2276 if( !captcha_is_correct(1) ){
2277 eErr = 2;
2278 zErr = mprintf("enter the security code shown below");
2279 bSubmit = 0;
@@ -3300,11 +3300,11 @@
3300 }
3301 if( P("submit")!=0
3302 && P("subject")!=0
3303 && P("msg")!=0
3304 && P("from")!=0
3305 && cgi_csrf_safe(2)
3306 && captcha_is_correct(0)
3307 ){
3308 Blob hdr, body;
3309 AlertSender *pSender = alert_sender_new(0,0);
3310 blob_init(&hdr, 0, 0);
@@ -3477,11 +3477,11 @@
3477 /* Visit the /announce/test1 page to see the CGI variables */
3478 zAction = "announce/test1";
3479 @ <p style='border: 1px solid black; padding: 1ex;'>
3480 cgi_print_all(0, 0, 0);
3481 @ </p>
3482 }else if( P("submit")!=0 && cgi_csrf_safe(2) ){
3483 char *zErr = alert_send_announcement();
3484 style_header("Announcement Sent");
3485 if( zErr ){
3486 @ <h1>Internal Error</h1>
3487 @ <p>The following error was reported by the system:
@@ -3502,10 +3502,11 @@
3502 return;
3503 }
3504
3505 style_header("Send Announcement");
3506 @ <form method="POST" action="%R/%s(zAction)">
3507 login_insert_csrf_secret();
3508 @ <table class="subscribe">
3509 if( g.perm.Admin ){
3510 int aa = PB("aa");
3511 int all = PB("all");
3512 int aMod = PB("mods");
3513
--- src/builtin.c
+++ src/builtin.c
@@ -666,18 +666,10 @@
666666
CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
667667
CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
668668
CX("};\n"/*fossil.user*/);
669669
CX("if(fossil.config.skin.isDark) "
670670
"document.body.classList.add('fossil-dark-style');\n");
671
-#if 0
672
- /* Is it safe to emit the CSRF token here? Some pages add it
673
- ** as a hidden form field. */
674
- if(g.zCsrfToken[0]!=0){
675
- CX("window.fossil.csrfToken = %!j;\n",
676
- g.zCsrfToken);
677
- }
678
-#endif
679671
/*
680672
** fossil.page holds info about the current page. This is also
681673
** where the current page "should" store any of its own
682674
** page-specific state, and it is reserved for that purpose.
683675
*/
684676
--- src/builtin.c
+++ src/builtin.c
@@ -666,18 +666,10 @@
666 CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
667 CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
668 CX("};\n"/*fossil.user*/);
669 CX("if(fossil.config.skin.isDark) "
670 "document.body.classList.add('fossil-dark-style');\n");
671 #if 0
672 /* Is it safe to emit the CSRF token here? Some pages add it
673 ** as a hidden form field. */
674 if(g.zCsrfToken[0]!=0){
675 CX("window.fossil.csrfToken = %!j;\n",
676 g.zCsrfToken);
677 }
678 #endif
679 /*
680 ** fossil.page holds info about the current page. This is also
681 ** where the current page "should" store any of its own
682 ** page-specific state, and it is reserved for that purpose.
683 */
684
--- src/builtin.c
+++ src/builtin.c
@@ -666,18 +666,10 @@
666 CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
667 CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
668 CX("};\n"/*fossil.user*/);
669 CX("if(fossil.config.skin.isDark) "
670 "document.body.classList.add('fossil-dark-style');\n");
 
 
 
 
 
 
 
 
671 /*
672 ** fossil.page holds info about the current page. This is also
673 ** where the current page "should" store any of its own
674 ** page-specific state, and it is reserved for that purpose.
675 */
676
+48 -26
--- src/cgi.c
+++ src/cgi.c
@@ -314,17 +314,15 @@
314314
if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){
315315
zSecure = " secure;";
316316
}
317317
if( lifetime!=0 ){
318318
blob_appendf(&extraHeader,
319
- "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; "
320
- "%s Version=1\r\n",
319
+ "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; %s\r\n",
321320
zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure);
322321
}else{
323322
blob_appendf(&extraHeader,
324
- "Set-Cookie: %s=%t; Path=%s; HttpOnly; "
325
- "%s Version=1\r\n",
323
+ "Set-Cookie: %s=%t; Path=%s; HttpOnly; %s\r\n",
326324
zName, zValue, zPath, zSecure);
327325
}
328326
}
329327
330328
@@ -700,42 +698,66 @@
700698
nBase = (int)strlen(g.zBaseURL);
701699
if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0;
702700
if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0;
703701
return 1;
704702
}
703
+
704
+/*
705
+** Return true if the current CGI request is a POST request
706
+*/
707
+static int cgi_is_post_request(void){
708
+ const char *zMethod = P("REQUEST_METHOD");
709
+ if( zMethod==0 ) return 0;
710
+ if( strcmp(zMethod,"POST")!=0 ) return 0;
711
+ return 1;
712
+}
705713
706714
/*
707715
** Return true if the current request appears to be safe from a
708
-** Cross-Site Request Forgery (CSRF) attack. Conditions that must
709
-** be met:
716
+** Cross-Site Request Forgery (CSRF) attack. The level of checking
717
+** is determined by the parameter. The higher the number, the more
718
+** secure we are:
719
+**
720
+** 0: Request must come from the same origin
721
+** 1: Same origin and must be a POST request
722
+** 2: All of the above plus must have a valid CSRF token
723
+**
724
+** Results are cached in the g.okCsrf variable. The g.okCsrf value
725
+** has meaning as follows:
710726
**
711
-** * The HTTP_REFERER must have the same origin
712
-** * The REQUEST_METHOD must be POST - or requirePost==0
727
+** -1: Not a secure request
728
+** 0: Status unknown
729
+** 1: Request comes from the same origin
730
+** 2: (1) plus it is a POST request
731
+** 3: (2) plus there is a valid "csrf" token in the request
713732
*/
714
-int cgi_csrf_safe(int requirePost){
715
- if( requirePost ){
716
- const char *zMethod = P("REQUEST_METHOD");
717
- if( zMethod==0 ) return 0;
718
- if( strcmp(zMethod,"POST")!=0 ) return 0;
733
+int cgi_csrf_safe(int securityLevel){
734
+ if( g.okCsrf<0 ) return 0;
735
+ if( g.okCsrf==0 ){
736
+ if( !cgi_same_origin() ){
737
+ g.okCsrf = -1;
738
+ }else{
739
+ g.okCsrf = 1;
740
+ if( cgi_is_post_request() ){
741
+ g.okCsrf = 2;
742
+ if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
743
+ g.okCsrf = 3;
744
+ }
745
+ }
746
+ }
719747
}
720
- return cgi_same_origin();
748
+ return g.okCsrf >= (securityLevel+1);
721749
}
722750
723751
/*
724
-** If bLoginVerifyCsrf is true, this calls login_verify_csrf() to
725
-** verify that the secret injected by login_insert_csrf_secret() is in
726
-** the CGI environment and valid. If that fails, it does so
727
-** fatally. If that passes and cgi_csrf_safe(1) returns false, this
728
-** fails fatally with a message about a cross-site scripting attempt,
729
-** else it returns without side effects.
752
+** Verify that CSRF defenses are maximal - that the request comes from
753
+** the same origin, that it is a POST request, and that there is a valid
754
+** "csrf" token. If this is not the case, fail immediately.
730755
*/
731
-void cgi_csrf_verify(int bLoginVerifyCsrf){
732
- if( bLoginVerifyCsrf!=0 ){
733
- login_verify_csrf_secret();
734
- }
735
- if( 0==cgi_csrf_safe(1) ){
736
- fossil_fatal("Cross-site request forgery attempt");
756
+void cgi_csrf_verify(void){
757
+ if( !cgi_csrf_safe(2) ){
758
+ fossil_fatal("Cross-site Request Forgery detected");
737759
}
738760
}
739761
740762
/*
741763
** Information about all query parameters, post parameter, cookies and
742764
--- src/cgi.c
+++ src/cgi.c
@@ -314,17 +314,15 @@
314 if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){
315 zSecure = " secure;";
316 }
317 if( lifetime!=0 ){
318 blob_appendf(&extraHeader,
319 "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; "
320 "%s Version=1\r\n",
321 zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure);
322 }else{
323 blob_appendf(&extraHeader,
324 "Set-Cookie: %s=%t; Path=%s; HttpOnly; "
325 "%s Version=1\r\n",
326 zName, zValue, zPath, zSecure);
327 }
328 }
329
330
@@ -700,42 +698,66 @@
700 nBase = (int)strlen(g.zBaseURL);
701 if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0;
702 if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0;
703 return 1;
704 }
 
 
 
 
 
 
 
 
 
 
705
706 /*
707 ** Return true if the current request appears to be safe from a
708 ** Cross-Site Request Forgery (CSRF) attack. Conditions that must
709 ** be met:
 
 
 
 
 
 
 
 
710 **
711 ** * The HTTP_REFERER must have the same origin
712 ** * The REQUEST_METHOD must be POST - or requirePost==0
 
 
 
713 */
714 int cgi_csrf_safe(int requirePost){
715 if( requirePost ){
716 const char *zMethod = P("REQUEST_METHOD");
717 if( zMethod==0 ) return 0;
718 if( strcmp(zMethod,"POST")!=0 ) return 0;
 
 
 
 
 
 
 
 
 
719 }
720 return cgi_same_origin();
721 }
722
723 /*
724 ** If bLoginVerifyCsrf is true, this calls login_verify_csrf() to
725 ** verify that the secret injected by login_insert_csrf_secret() is in
726 ** the CGI environment and valid. If that fails, it does so
727 ** fatally. If that passes and cgi_csrf_safe(1) returns false, this
728 ** fails fatally with a message about a cross-site scripting attempt,
729 ** else it returns without side effects.
730 */
731 void cgi_csrf_verify(int bLoginVerifyCsrf){
732 if( bLoginVerifyCsrf!=0 ){
733 login_verify_csrf_secret();
734 }
735 if( 0==cgi_csrf_safe(1) ){
736 fossil_fatal("Cross-site request forgery attempt");
737 }
738 }
739
740 /*
741 ** Information about all query parameters, post parameter, cookies and
742
--- src/cgi.c
+++ src/cgi.c
@@ -314,17 +314,15 @@
314 if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){
315 zSecure = " secure;";
316 }
317 if( lifetime!=0 ){
318 blob_appendf(&extraHeader,
319 "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; %s\r\n",
 
320 zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure);
321 }else{
322 blob_appendf(&extraHeader,
323 "Set-Cookie: %s=%t; Path=%s; HttpOnly; %s\r\n",
 
324 zName, zValue, zPath, zSecure);
325 }
326 }
327
328
@@ -700,42 +698,66 @@
698 nBase = (int)strlen(g.zBaseURL);
699 if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0;
700 if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0;
701 return 1;
702 }
703
704 /*
705 ** Return true if the current CGI request is a POST request
706 */
707 static int cgi_is_post_request(void){
708 const char *zMethod = P("REQUEST_METHOD");
709 if( zMethod==0 ) return 0;
710 if( strcmp(zMethod,"POST")!=0 ) return 0;
711 return 1;
712 }
713
714 /*
715 ** Return true if the current request appears to be safe from a
716 ** Cross-Site Request Forgery (CSRF) attack. The level of checking
717 ** is determined by the parameter. The higher the number, the more
718 ** secure we are:
719 **
720 ** 0: Request must come from the same origin
721 ** 1: Same origin and must be a POST request
722 ** 2: All of the above plus must have a valid CSRF token
723 **
724 ** Results are cached in the g.okCsrf variable. The g.okCsrf value
725 ** has meaning as follows:
726 **
727 ** -1: Not a secure request
728 ** 0: Status unknown
729 ** 1: Request comes from the same origin
730 ** 2: (1) plus it is a POST request
731 ** 3: (2) plus there is a valid "csrf" token in the request
732 */
733 int cgi_csrf_safe(int securityLevel){
734 if( g.okCsrf<0 ) return 0;
735 if( g.okCsrf==0 ){
736 if( !cgi_same_origin() ){
737 g.okCsrf = -1;
738 }else{
739 g.okCsrf = 1;
740 if( cgi_is_post_request() ){
741 g.okCsrf = 2;
742 if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
743 g.okCsrf = 3;
744 }
745 }
746 }
747 }
748 return g.okCsrf >= (securityLevel+1);
749 }
750
751 /*
752 ** Verify that CSRF defenses are maximal - that the request comes from
753 ** the same origin, that it is a POST request, and that there is a valid
754 ** "csrf" token. If this is not the case, fail immediately.
 
 
 
755 */
756 void cgi_csrf_verify(void){
757 if( !cgi_csrf_safe(2) ){
758 fossil_fatal("Cross-site Request Forgery detected");
 
 
 
759 }
760 }
761
762 /*
763 ** Information about all query parameters, post parameter, cookies and
764
+1 -2
--- src/event.c
+++ src/event.c
@@ -468,12 +468,11 @@
468468
rid
469469
);
470470
}
471471
}
472472
zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
473
- if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){
474
- login_verify_csrf_secret();
473
+ if( P("submit")!=0 && (zBody!=0 && zComment!=0) && cgi_csrf_safe(2) ){
475474
if ( !event_commit_common(rid, zId, zBody, zETime,
476475
zMimetype, zComment, zTags,
477476
zClrFlag[0] ? zClr : 0) ){
478477
style_header("Error");
479478
@ Internal error: Fossil tried to make an invalid artifact for
480479
--- src/event.c
+++ src/event.c
@@ -468,12 +468,11 @@
468 rid
469 );
470 }
471 }
472 zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
473 if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){
474 login_verify_csrf_secret();
475 if ( !event_commit_common(rid, zId, zBody, zETime,
476 zMimetype, zComment, zTags,
477 zClrFlag[0] ? zClr : 0) ){
478 style_header("Error");
479 @ Internal error: Fossil tried to make an invalid artifact for
480
--- src/event.c
+++ src/event.c
@@ -468,12 +468,11 @@
468 rid
469 );
470 }
471 }
472 zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
473 if( P("submit")!=0 && (zBody!=0 && zComment!=0) && cgi_csrf_safe(2) ){
 
474 if ( !event_commit_common(rid, zId, zBody, zETime,
475 zMimetype, zComment, zTags,
476 zClrFlag[0] ? zClr : 0) ){
477 style_header("Error");
478 @ Internal error: Fossil tried to make an invalid artifact for
479
+9 -5
--- src/forum.c
+++ src/forum.c
@@ -897,10 +897,11 @@
897897
}
898898
}else if( bSameUser ){
899899
/* Allow users to delete (reject) their own pending posts. */
900900
@ <input type="submit" name="reject" value="Delete">
901901
}
902
+ login_insert_csrf_secret();
902903
@ </form>
903904
if( bSelect && forumpost_may_close() && iClosed>=0 ){
904905
int iHead = forumpost_head_rid(p->fpid);
905906
@ <form method="post" \
906907
@ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
@@ -1423,11 +1424,11 @@
14231424
login_check_credentials();
14241425
if( forumpost_may_close()==0 ){
14251426
login_needed(g.anon.Admin);
14261427
return;
14271428
}
1428
- cgi_csrf_verify(1);
1429
+ cgi_csrf_verify();
14291430
fpid = symbolic_name_to_rid(zFpid, "f");
14301431
if( fpid<=0 ){
14311432
webpage_error("Missing or invalid fpid query parameter");
14321433
}
14331434
fClose = sqlite3_strglob("*_close*", g.zPath)==0;
@@ -1539,11 +1540,11 @@
15391540
login_check_credentials();
15401541
if( !g.perm.WrForum ){
15411542
login_needed(g.anon.WrForum);
15421543
return;
15431544
}
1544
- if( P("submit") && cgi_csrf_safe(1) ){
1545
+ if( P("submit") && cgi_csrf_safe(2) ){
15451546
if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent,
15461547
forum_post_flags()) ) return;
15471548
}
15481549
if( P("preview") && !whitespace_only(zContent) ){
15491550
@ <h1>Preview:</h1>
@@ -1560,10 +1561,11 @@
15601561
@ <input type="submit" name="submit" value="Submit">
15611562
}else{
15621563
@ <input type="submit" name="submit" value="Submit" disabled>
15631564
}
15641565
forum_render_debug_options();
1566
+ login_insert_csrf_secret();
15651567
@ </form>
15661568
forum_emit_js();
15671569
style_finish_page();
15681570
}
15691571
@@ -1611,11 +1613,11 @@
16111613
return;
16121614
}
16131615
bPreview = P("preview")!=0;
16141616
bReply = P("reply")!=0;
16151617
iClosed = forum_rid_is_closed(fpid, 1);
1616
- isCsrfSafe = cgi_csrf_safe(1);
1618
+ isCsrfSafe = cgi_csrf_safe(2);
16171619
bPrivate = content_is_private(fpid);
16181620
bSameUser = login_is_individual()
16191621
&& fossil_strcmp(pPost->zUser, g.zLogin)==0;
16201622
if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
16211623
if( g.perm.ModForum && P("approve") ){
@@ -1679,10 +1681,11 @@
16791681
forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
16801682
"forumEdit", 1);
16811683
@ <h1>Change Into:</h1>
16821684
forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
16831685
@ <form action="%R/forume2" method="POST">
1686
+ login_insert_csrf_secret();
16841687
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
16851688
@ <input type="hidden" name="nullout" value="1">
16861689
@ <input type="hidden" name="mimetype" value="%h(zMimetype)">
16871690
@ <input type="hidden" name="content" value="%h(zContent)">
16881691
if( zTitle ){
@@ -1706,10 +1709,11 @@
17061709
@ <h2>Preview of Edited Post:</h2>
17071710
forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
17081711
}
17091712
@ <h2>Revised Message:</h2>
17101713
@ <form action="%R/forume2" method="POST">
1714
+ login_insert_csrf_secret();
17111715
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
17121716
@ <input type="hidden" name="edit" value="1">
17131717
forum_from_line();
17141718
forum_post_widget(zTitle, zMimetype, zContent);
17151719
}else{
@@ -1750,10 +1754,11 @@
17501754
if( !iClosed || g.perm.Admin ) {
17511755
@ <input type="submit" name="submit" value="Submit">
17521756
}
17531757
}
17541758
forum_render_debug_options();
1759
+ login_insert_csrf_secret();
17551760
@ </form>
17561761
forum_emit_js();
17571762
style_finish_page();
17581763
}
17591764
@@ -1842,14 +1847,13 @@
18421847
}
18431848
}
18441849
18451850
@ <h2>Settings</h2>
18461851
@ <p>Configuration settings specific to the forum.</p>
1847
- if( P("submit") && cgi_csrf_safe(1) ){
1852
+ if( P("submit") && cgi_csrf_safe(2) ){
18481853
int i = 0;
18491854
const char *zSetting;
1850
- login_verify_csrf_secret();
18511855
db_begin_transaction();
18521856
while( (zSetting = zSettingsBool[i++]) ){
18531857
const char *z = P(zSetting);
18541858
if( !z || !z[0] ) z = "off";
18551859
db_set(zSetting/*works-like:"x"*/, z, 0);
18561860
--- src/forum.c
+++ src/forum.c
@@ -897,10 +897,11 @@
897 }
898 }else if( bSameUser ){
899 /* Allow users to delete (reject) their own pending posts. */
900 @ <input type="submit" name="reject" value="Delete">
901 }
 
902 @ </form>
903 if( bSelect && forumpost_may_close() && iClosed>=0 ){
904 int iHead = forumpost_head_rid(p->fpid);
905 @ <form method="post" \
906 @ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
@@ -1423,11 +1424,11 @@
1423 login_check_credentials();
1424 if( forumpost_may_close()==0 ){
1425 login_needed(g.anon.Admin);
1426 return;
1427 }
1428 cgi_csrf_verify(1);
1429 fpid = symbolic_name_to_rid(zFpid, "f");
1430 if( fpid<=0 ){
1431 webpage_error("Missing or invalid fpid query parameter");
1432 }
1433 fClose = sqlite3_strglob("*_close*", g.zPath)==0;
@@ -1539,11 +1540,11 @@
1539 login_check_credentials();
1540 if( !g.perm.WrForum ){
1541 login_needed(g.anon.WrForum);
1542 return;
1543 }
1544 if( P("submit") && cgi_csrf_safe(1) ){
1545 if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent,
1546 forum_post_flags()) ) return;
1547 }
1548 if( P("preview") && !whitespace_only(zContent) ){
1549 @ <h1>Preview:</h1>
@@ -1560,10 +1561,11 @@
1560 @ <input type="submit" name="submit" value="Submit">
1561 }else{
1562 @ <input type="submit" name="submit" value="Submit" disabled>
1563 }
1564 forum_render_debug_options();
 
1565 @ </form>
1566 forum_emit_js();
1567 style_finish_page();
1568 }
1569
@@ -1611,11 +1613,11 @@
1611 return;
1612 }
1613 bPreview = P("preview")!=0;
1614 bReply = P("reply")!=0;
1615 iClosed = forum_rid_is_closed(fpid, 1);
1616 isCsrfSafe = cgi_csrf_safe(1);
1617 bPrivate = content_is_private(fpid);
1618 bSameUser = login_is_individual()
1619 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
1620 if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
1621 if( g.perm.ModForum && P("approve") ){
@@ -1679,10 +1681,11 @@
1679 forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
1680 "forumEdit", 1);
1681 @ <h1>Change Into:</h1>
1682 forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
1683 @ <form action="%R/forume2" method="POST">
 
1684 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
1685 @ <input type="hidden" name="nullout" value="1">
1686 @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
1687 @ <input type="hidden" name="content" value="%h(zContent)">
1688 if( zTitle ){
@@ -1706,10 +1709,11 @@
1706 @ <h2>Preview of Edited Post:</h2>
1707 forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
1708 }
1709 @ <h2>Revised Message:</h2>
1710 @ <form action="%R/forume2" method="POST">
 
1711 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
1712 @ <input type="hidden" name="edit" value="1">
1713 forum_from_line();
1714 forum_post_widget(zTitle, zMimetype, zContent);
1715 }else{
@@ -1750,10 +1754,11 @@
1750 if( !iClosed || g.perm.Admin ) {
1751 @ <input type="submit" name="submit" value="Submit">
1752 }
1753 }
1754 forum_render_debug_options();
 
1755 @ </form>
1756 forum_emit_js();
1757 style_finish_page();
1758 }
1759
@@ -1842,14 +1847,13 @@
1842 }
1843 }
1844
1845 @ <h2>Settings</h2>
1846 @ <p>Configuration settings specific to the forum.</p>
1847 if( P("submit") && cgi_csrf_safe(1) ){
1848 int i = 0;
1849 const char *zSetting;
1850 login_verify_csrf_secret();
1851 db_begin_transaction();
1852 while( (zSetting = zSettingsBool[i++]) ){
1853 const char *z = P(zSetting);
1854 if( !z || !z[0] ) z = "off";
1855 db_set(zSetting/*works-like:"x"*/, z, 0);
1856
--- src/forum.c
+++ src/forum.c
@@ -897,10 +897,11 @@
897 }
898 }else if( bSameUser ){
899 /* Allow users to delete (reject) their own pending posts. */
900 @ <input type="submit" name="reject" value="Delete">
901 }
902 login_insert_csrf_secret();
903 @ </form>
904 if( bSelect && forumpost_may_close() && iClosed>=0 ){
905 int iHead = forumpost_head_rid(p->fpid);
906 @ <form method="post" \
907 @ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
@@ -1423,11 +1424,11 @@
1424 login_check_credentials();
1425 if( forumpost_may_close()==0 ){
1426 login_needed(g.anon.Admin);
1427 return;
1428 }
1429 cgi_csrf_verify();
1430 fpid = symbolic_name_to_rid(zFpid, "f");
1431 if( fpid<=0 ){
1432 webpage_error("Missing or invalid fpid query parameter");
1433 }
1434 fClose = sqlite3_strglob("*_close*", g.zPath)==0;
@@ -1539,11 +1540,11 @@
1540 login_check_credentials();
1541 if( !g.perm.WrForum ){
1542 login_needed(g.anon.WrForum);
1543 return;
1544 }
1545 if( P("submit") && cgi_csrf_safe(2) ){
1546 if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent,
1547 forum_post_flags()) ) return;
1548 }
1549 if( P("preview") && !whitespace_only(zContent) ){
1550 @ <h1>Preview:</h1>
@@ -1560,10 +1561,11 @@
1561 @ <input type="submit" name="submit" value="Submit">
1562 }else{
1563 @ <input type="submit" name="submit" value="Submit" disabled>
1564 }
1565 forum_render_debug_options();
1566 login_insert_csrf_secret();
1567 @ </form>
1568 forum_emit_js();
1569 style_finish_page();
1570 }
1571
@@ -1611,11 +1613,11 @@
1613 return;
1614 }
1615 bPreview = P("preview")!=0;
1616 bReply = P("reply")!=0;
1617 iClosed = forum_rid_is_closed(fpid, 1);
1618 isCsrfSafe = cgi_csrf_safe(2);
1619 bPrivate = content_is_private(fpid);
1620 bSameUser = login_is_individual()
1621 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
1622 if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
1623 if( g.perm.ModForum && P("approve") ){
@@ -1679,10 +1681,11 @@
1681 forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
1682 "forumEdit", 1);
1683 @ <h1>Change Into:</h1>
1684 forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
1685 @ <form action="%R/forume2" method="POST">
1686 login_insert_csrf_secret();
1687 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
1688 @ <input type="hidden" name="nullout" value="1">
1689 @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
1690 @ <input type="hidden" name="content" value="%h(zContent)">
1691 if( zTitle ){
@@ -1706,10 +1709,11 @@
1709 @ <h2>Preview of Edited Post:</h2>
1710 forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
1711 }
1712 @ <h2>Revised Message:</h2>
1713 @ <form action="%R/forume2" method="POST">
1714 login_insert_csrf_secret();
1715 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
1716 @ <input type="hidden" name="edit" value="1">
1717 forum_from_line();
1718 forum_post_widget(zTitle, zMimetype, zContent);
1719 }else{
@@ -1750,10 +1754,11 @@
1754 if( !iClosed || g.perm.Admin ) {
1755 @ <input type="submit" name="submit" value="Submit">
1756 }
1757 }
1758 forum_render_debug_options();
1759 login_insert_csrf_secret();
1760 @ </form>
1761 forum_emit_js();
1762 style_finish_page();
1763 }
1764
@@ -1842,14 +1847,13 @@
1847 }
1848 }
1849
1850 @ <h2>Settings</h2>
1851 @ <p>Configuration settings specific to the forum.</p>
1852 if( P("submit") && cgi_csrf_safe(2) ){
1853 int i = 0;
1854 const char *zSetting;
 
1855 db_begin_transaction();
1856 while( (zSetting = zSettingsBool[i++]) ){
1857 const char *z = P(zSetting);
1858 if( !z || !z[0] ) z = "off";
1859 db_set(zSetting/*works-like:"x"*/, z, 0);
1860
+1 -3
--- src/info.c
+++ src/info.c
@@ -3213,15 +3213,14 @@
32133213
zNewTag = PDT("tagname","");
32143214
zNewBrFlag = P("newbr") ? " checked" : "";
32153215
zNewBranch = PDT("brname","");
32163216
zCloseFlag = P("close") ? " checked" : "";
32173217
zHideFlag = P("hide") ? " checked" : "";
3218
- if( P("apply") && cgi_csrf_safe(1) ){
3218
+ if( P("apply") && cgi_csrf_safe(2) ){
32193219
Blob ctrl;
32203220
char *zNow;
32213221
3222
- login_verify_csrf_secret();
32233222
blob_zero(&ctrl);
32243223
zNow = date_in_standard_format(zChngTime ? zChngTime : "now");
32253224
blob_appendf(&ctrl, "D %s\n", zNow);
32263225
init_newtags();
32273226
if( zNewColorFlag[0]
@@ -3300,11 +3299,10 @@
33003299
blob_reset(&suffix);
33013300
}
33023301
@ <p>Make changes to attributes of check-in
33033302
@ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p>
33043303
form_begin(0, "%R/ci_edit");
3305
- login_insert_csrf_secret();
33063304
@ <div><input type="hidden" name="r" value="%s(zUuid)">
33073305
@ <table border="0" cellspacing="10">
33083306
33093307
@ <tr><th align="right" valign="top">User:</th>
33103308
@ <td valign="top">
33113309
--- src/info.c
+++ src/info.c
@@ -3213,15 +3213,14 @@
3213 zNewTag = PDT("tagname","");
3214 zNewBrFlag = P("newbr") ? " checked" : "";
3215 zNewBranch = PDT("brname","");
3216 zCloseFlag = P("close") ? " checked" : "";
3217 zHideFlag = P("hide") ? " checked" : "";
3218 if( P("apply") && cgi_csrf_safe(1) ){
3219 Blob ctrl;
3220 char *zNow;
3221
3222 login_verify_csrf_secret();
3223 blob_zero(&ctrl);
3224 zNow = date_in_standard_format(zChngTime ? zChngTime : "now");
3225 blob_appendf(&ctrl, "D %s\n", zNow);
3226 init_newtags();
3227 if( zNewColorFlag[0]
@@ -3300,11 +3299,10 @@
3300 blob_reset(&suffix);
3301 }
3302 @ <p>Make changes to attributes of check-in
3303 @ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p>
3304 form_begin(0, "%R/ci_edit");
3305 login_insert_csrf_secret();
3306 @ <div><input type="hidden" name="r" value="%s(zUuid)">
3307 @ <table border="0" cellspacing="10">
3308
3309 @ <tr><th align="right" valign="top">User:</th>
3310 @ <td valign="top">
3311
--- src/info.c
+++ src/info.c
@@ -3213,15 +3213,14 @@
3213 zNewTag = PDT("tagname","");
3214 zNewBrFlag = P("newbr") ? " checked" : "";
3215 zNewBranch = PDT("brname","");
3216 zCloseFlag = P("close") ? " checked" : "";
3217 zHideFlag = P("hide") ? " checked" : "";
3218 if( P("apply") && cgi_csrf_safe(2) ){
3219 Blob ctrl;
3220 char *zNow;
3221
 
3222 blob_zero(&ctrl);
3223 zNow = date_in_standard_format(zChngTime ? zChngTime : "now");
3224 blob_appendf(&ctrl, "D %s\n", zNow);
3225 init_newtags();
3226 if( zNewColorFlag[0]
@@ -3300,11 +3299,10 @@
3299 blob_reset(&suffix);
3300 }
3301 @ <p>Make changes to attributes of check-in
3302 @ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p>
3303 form_begin(0, "%R/ci_edit");
 
3304 @ <div><input type="hidden" name="r" value="%s(zUuid)">
3305 @ <table border="0" cellspacing="10">
3306
3307 @ <tr><th align="right" valign="top">User:</th>
3308 @ <td valign="top">
3309
+1 -1
--- src/interwiki.c
+++ src/interwiki.c
@@ -314,11 +314,11 @@
314314
login_check_credentials();
315315
if( !g.perm.Read && !g.perm.RdWiki && ~g.perm.RdTkt ){
316316
login_needed(0);
317317
return;
318318
}
319
- if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(1) ){
319
+ if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(2) ){
320320
zTag = PT("tag");
321321
zBase = PT("base");
322322
zHash = PT("hash");
323323
zWiki = PT("wiki");
324324
if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){
325325
--- src/interwiki.c
+++ src/interwiki.c
@@ -314,11 +314,11 @@
314 login_check_credentials();
315 if( !g.perm.Read && !g.perm.RdWiki && ~g.perm.RdTkt ){
316 login_needed(0);
317 return;
318 }
319 if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(1) ){
320 zTag = PT("tag");
321 zBase = PT("base");
322 zHash = PT("hash");
323 zWiki = PT("wiki");
324 if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){
325
--- src/interwiki.c
+++ src/interwiki.c
@@ -314,11 +314,11 @@
314 login_check_credentials();
315 if( !g.perm.Read && !g.perm.RdWiki && ~g.perm.RdTkt ){
316 login_needed(0);
317 return;
318 }
319 if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(2) ){
320 zTag = PT("tag");
321 zBase = PT("base");
322 zHash = PT("hash");
323 zWiki = PT("wiki");
324 if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){
325
+26 -22
--- src/login.c
+++ src/login.c
@@ -49,10 +49,25 @@
4949
# define sleep Sleep /* windows does not have sleep, but Sleep */
5050
# endif
5151
#endif
5252
#include <time.h>
5353
54
+/*
55
+** Compute an appropriate Anti-CSRF token into g.zCsrfToken[].
56
+*/
57
+static void login_create_csrf_secret(const char *zSeed){
58
+ unsigned char zResult[20];
59
+ int i;
60
+
61
+ sha1sum_binary(zSeed, zResult);
62
+ for(i=0; i<sizeof(g.zCsrfToken)-1; i++){
63
+ g.zCsrfToken[i] = "abcdefghijklmnopqrstuvwxyz"
64
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
65
+ "0123456789-/"[zResult[i]%64];
66
+ }
67
+ g.zCsrfToken[i] = 0;
68
+}
5469
5570
/*
5671
** Return the login-group name. Or return 0 if this repository is
5772
** not a member of a login-group.
5873
*/
@@ -583,11 +598,11 @@
583598
constant_time_cmp_function, 0, 0);
584599
zUsername = P("u");
585600
zPasswd = P("p");
586601
anonFlag = g.zLogin==0 && PB("anon");
587602
/* Handle log-out requests */
588
- if( P("out") ){
603
+ if( P("out") && cgi_csrf_safe(2) ){
589604
login_clear_login_data();
590605
redirect_to_g();
591606
return;
592607
}
593608
@@ -598,10 +613,11 @@
598613
}
599614
600615
/* Deal with password-change requests */
601616
if( g.perm.Password && zPasswd
602617
&& (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
618
+ && cgi_csrf_safe(2)
603619
){
604620
/* If there is not a "real" login, we cannot change any password. */
605621
if( g.zLogin ){
606622
/* The user requests a password change */
607623
zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
@@ -1288,10 +1304,11 @@
12881304
|| (g.fSshClient & CGI_SSH_CLIENT)!=0 )
12891305
&& g.useLocalauth
12901306
&& db_get_int("localauth",0)==0
12911307
&& P("HTTPS")==0
12921308
){
1309
+ char *zSeed;
12931310
if( g.localOpen ) zLogin = db_lget("default-user",0);
12941311
if( zLogin!=0 ){
12951312
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
12961313
}else{
12971314
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
@@ -1298,11 +1315,14 @@
12981315
}
12991316
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
13001317
zCap = "sxy";
13011318
g.noPswd = 1;
13021319
g.isHuman = 1;
1303
- sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
1320
+ zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)"
1321
+ " FROM user WHERE uid=%d", uid);
1322
+ login_create_csrf_secret(zSeed);
1323
+ fossil_free(zSeed);
13041324
}
13051325
13061326
/* Check the login cookie to see if it matches a known valid user.
13071327
*/
13081328
if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){
@@ -1353,11 +1373,11 @@
13531373
if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
13541374
uid = login_find_user(zUser, zHash);
13551375
if( uid ) record_login_attempt(zUser, zIpAddr, 1);
13561376
}
13571377
}
1358
- sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash);
1378
+ login_create_csrf_secret(zHash);
13591379
}
13601380
13611381
/* If no user found and the REMOTE_USER environment variable is set,
13621382
** then accept the value of REMOTE_USER as the user.
13631383
*/
@@ -1403,11 +1423,11 @@
14031423
if( uid==0 ){
14041424
/* If there is no user "nobody", then make one up - with no privileges */
14051425
uid = -1;
14061426
zCap = "";
14071427
}
1408
- sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "none");
1428
+ login_create_csrf_secret("none");
14091429
}
14101430
14111431
login_set_uid(uid, zCap);
14121432
}
14131433
@@ -1805,26 +1825,10 @@
18051825
*/
18061826
void login_insert_csrf_secret(void){
18071827
@ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)">
18081828
}
18091829
1810
-/*
1811
-** Before using the results of a form, first call this routine to verify
1812
-** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
1813
-** is missing or is incorrect, that indicates a cross-site scripting attack.
1814
-** If the event of an attack is detected, an error message is generated and
1815
-** all further processing is aborted.
1816
-*/
1817
-void login_verify_csrf_secret(void){
1818
- if( g.okCsrf ) return;
1819
- if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
1820
- g.okCsrf = 1;
1821
- return;
1822
- }
1823
- fossil_fatal("Cross-site request forgery attempt");
1824
-}
1825
-
18261830
/*
18271831
** Check to see if the candidate username zUserID is already used.
18281832
** Return 1 if it is already in use. Return 0 if the name is
18291833
** available for a self-registeration.
18301834
*/
@@ -1978,11 +1982,11 @@
19781982
zConfirm = PDT("cp","");
19791983
zEAddr = PDT("ea","");
19801984
zDName = PDT("dn","");
19811985
19821986
/* Verify user imputs */
1983
- if( P("new")==0 || !cgi_csrf_safe(1) ){
1987
+ if( P("new")==0 || !cgi_csrf_safe(2) ){
19841988
/* This is not a valid form submission. Fall through into
19851989
** the form display */
19861990
}else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
19871991
iErrLine = 6;
19881992
zErr = "Incorrect CAPTCHA";
@@ -2256,11 +2260,11 @@
22562260
return;
22572261
}
22582262
zEAddr = PDT("ea","");
22592263
22602264
/* Verify user imputs */
2261
- if( !cgi_csrf_safe(1) || P("reqpwreset")==0 ){
2265
+ if( !cgi_csrf_safe(2) || P("reqpwreset")==0 ){
22622266
/* This is the initial display of the form. No processing or error
22632267
** checking is to be done. Fall through into the form display
22642268
*/
22652269
}else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
22662270
iErrLine = 2;
22672271
--- src/login.c
+++ src/login.c
@@ -49,10 +49,25 @@
49 # define sleep Sleep /* windows does not have sleep, but Sleep */
50 # endif
51 #endif
52 #include <time.h>
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
55 /*
56 ** Return the login-group name. Or return 0 if this repository is
57 ** not a member of a login-group.
58 */
@@ -583,11 +598,11 @@
583 constant_time_cmp_function, 0, 0);
584 zUsername = P("u");
585 zPasswd = P("p");
586 anonFlag = g.zLogin==0 && PB("anon");
587 /* Handle log-out requests */
588 if( P("out") ){
589 login_clear_login_data();
590 redirect_to_g();
591 return;
592 }
593
@@ -598,10 +613,11 @@
598 }
599
600 /* Deal with password-change requests */
601 if( g.perm.Password && zPasswd
602 && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
 
603 ){
604 /* If there is not a "real" login, we cannot change any password. */
605 if( g.zLogin ){
606 /* The user requests a password change */
607 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
@@ -1288,10 +1304,11 @@
1288 || (g.fSshClient & CGI_SSH_CLIENT)!=0 )
1289 && g.useLocalauth
1290 && db_get_int("localauth",0)==0
1291 && P("HTTPS")==0
1292 ){
 
1293 if( g.localOpen ) zLogin = db_lget("default-user",0);
1294 if( zLogin!=0 ){
1295 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
1296 }else{
1297 uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
@@ -1298,11 +1315,14 @@
1298 }
1299 g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
1300 zCap = "sxy";
1301 g.noPswd = 1;
1302 g.isHuman = 1;
1303 sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
 
 
 
1304 }
1305
1306 /* Check the login cookie to see if it matches a known valid user.
1307 */
1308 if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){
@@ -1353,11 +1373,11 @@
1353 if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
1354 uid = login_find_user(zUser, zHash);
1355 if( uid ) record_login_attempt(zUser, zIpAddr, 1);
1356 }
1357 }
1358 sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash);
1359 }
1360
1361 /* If no user found and the REMOTE_USER environment variable is set,
1362 ** then accept the value of REMOTE_USER as the user.
1363 */
@@ -1403,11 +1423,11 @@
1403 if( uid==0 ){
1404 /* If there is no user "nobody", then make one up - with no privileges */
1405 uid = -1;
1406 zCap = "";
1407 }
1408 sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "none");
1409 }
1410
1411 login_set_uid(uid, zCap);
1412 }
1413
@@ -1805,26 +1825,10 @@
1805 */
1806 void login_insert_csrf_secret(void){
1807 @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)">
1808 }
1809
1810 /*
1811 ** Before using the results of a form, first call this routine to verify
1812 ** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
1813 ** is missing or is incorrect, that indicates a cross-site scripting attack.
1814 ** If the event of an attack is detected, an error message is generated and
1815 ** all further processing is aborted.
1816 */
1817 void login_verify_csrf_secret(void){
1818 if( g.okCsrf ) return;
1819 if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
1820 g.okCsrf = 1;
1821 return;
1822 }
1823 fossil_fatal("Cross-site request forgery attempt");
1824 }
1825
1826 /*
1827 ** Check to see if the candidate username zUserID is already used.
1828 ** Return 1 if it is already in use. Return 0 if the name is
1829 ** available for a self-registeration.
1830 */
@@ -1978,11 +1982,11 @@
1978 zConfirm = PDT("cp","");
1979 zEAddr = PDT("ea","");
1980 zDName = PDT("dn","");
1981
1982 /* Verify user imputs */
1983 if( P("new")==0 || !cgi_csrf_safe(1) ){
1984 /* This is not a valid form submission. Fall through into
1985 ** the form display */
1986 }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
1987 iErrLine = 6;
1988 zErr = "Incorrect CAPTCHA";
@@ -2256,11 +2260,11 @@
2256 return;
2257 }
2258 zEAddr = PDT("ea","");
2259
2260 /* Verify user imputs */
2261 if( !cgi_csrf_safe(1) || P("reqpwreset")==0 ){
2262 /* This is the initial display of the form. No processing or error
2263 ** checking is to be done. Fall through into the form display
2264 */
2265 }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
2266 iErrLine = 2;
2267
--- src/login.c
+++ src/login.c
@@ -49,10 +49,25 @@
49 # define sleep Sleep /* windows does not have sleep, but Sleep */
50 # endif
51 #endif
52 #include <time.h>
53
54 /*
55 ** Compute an appropriate Anti-CSRF token into g.zCsrfToken[].
56 */
57 static void login_create_csrf_secret(const char *zSeed){
58 unsigned char zResult[20];
59 int i;
60
61 sha1sum_binary(zSeed, zResult);
62 for(i=0; i<sizeof(g.zCsrfToken)-1; i++){
63 g.zCsrfToken[i] = "abcdefghijklmnopqrstuvwxyz"
64 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
65 "0123456789-/"[zResult[i]%64];
66 }
67 g.zCsrfToken[i] = 0;
68 }
69
70 /*
71 ** Return the login-group name. Or return 0 if this repository is
72 ** not a member of a login-group.
73 */
@@ -583,11 +598,11 @@
598 constant_time_cmp_function, 0, 0);
599 zUsername = P("u");
600 zPasswd = P("p");
601 anonFlag = g.zLogin==0 && PB("anon");
602 /* Handle log-out requests */
603 if( P("out") && cgi_csrf_safe(2) ){
604 login_clear_login_data();
605 redirect_to_g();
606 return;
607 }
608
@@ -598,10 +613,11 @@
613 }
614
615 /* Deal with password-change requests */
616 if( g.perm.Password && zPasswd
617 && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
618 && cgi_csrf_safe(2)
619 ){
620 /* If there is not a "real" login, we cannot change any password. */
621 if( g.zLogin ){
622 /* The user requests a password change */
623 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
@@ -1288,10 +1304,11 @@
1304 || (g.fSshClient & CGI_SSH_CLIENT)!=0 )
1305 && g.useLocalauth
1306 && db_get_int("localauth",0)==0
1307 && P("HTTPS")==0
1308 ){
1309 char *zSeed;
1310 if( g.localOpen ) zLogin = db_lget("default-user",0);
1311 if( zLogin!=0 ){
1312 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
1313 }else{
1314 uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
@@ -1298,11 +1315,14 @@
1315 }
1316 g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
1317 zCap = "sxy";
1318 g.noPswd = 1;
1319 g.isHuman = 1;
1320 zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)"
1321 " FROM user WHERE uid=%d", uid);
1322 login_create_csrf_secret(zSeed);
1323 fossil_free(zSeed);
1324 }
1325
1326 /* Check the login cookie to see if it matches a known valid user.
1327 */
1328 if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){
@@ -1353,11 +1373,11 @@
1373 if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
1374 uid = login_find_user(zUser, zHash);
1375 if( uid ) record_login_attempt(zUser, zIpAddr, 1);
1376 }
1377 }
1378 login_create_csrf_secret(zHash);
1379 }
1380
1381 /* If no user found and the REMOTE_USER environment variable is set,
1382 ** then accept the value of REMOTE_USER as the user.
1383 */
@@ -1403,11 +1423,11 @@
1423 if( uid==0 ){
1424 /* If there is no user "nobody", then make one up - with no privileges */
1425 uid = -1;
1426 zCap = "";
1427 }
1428 login_create_csrf_secret("none");
1429 }
1430
1431 login_set_uid(uid, zCap);
1432 }
1433
@@ -1805,26 +1825,10 @@
1825 */
1826 void login_insert_csrf_secret(void){
1827 @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)">
1828 }
1829
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1830 /*
1831 ** Check to see if the candidate username zUserID is already used.
1832 ** Return 1 if it is already in use. Return 0 if the name is
1833 ** available for a self-registeration.
1834 */
@@ -1978,11 +1982,11 @@
1982 zConfirm = PDT("cp","");
1983 zEAddr = PDT("ea","");
1984 zDName = PDT("dn","");
1985
1986 /* Verify user imputs */
1987 if( P("new")==0 || !cgi_csrf_safe(2) ){
1988 /* This is not a valid form submission. Fall through into
1989 ** the form display */
1990 }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
1991 iErrLine = 6;
1992 zErr = "Incorrect CAPTCHA";
@@ -2256,11 +2260,11 @@
2260 return;
2261 }
2262 zEAddr = PDT("ea","");
2263
2264 /* Verify user imputs */
2265 if( !cgi_csrf_safe(2) || P("reqpwreset")==0 ){
2266 /* This is the initial display of the form. No processing or error
2267 ** checking is to be done. Fall through into the form display
2268 */
2269 }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
2270 iErrLine = 2;
2271
+6 -2
--- src/main.c
+++ src/main.c
@@ -256,12 +256,16 @@
256256
/* all Tcl related context necessary for integration */
257257
struct TclContext tcl;
258258
#endif
259259
260260
/* For defense against Cross-site Request Forgery attacks */
261
- char zCsrfToken[12]; /* Value of the anti-CSRF token */
262
- int okCsrf; /* Anti-CSRF token is present and valid */
261
+ char zCsrfToken[16]; /* Value of the anti-CSRF token */
262
+ int okCsrf; /* -1: unsafe
263
+ ** 0: unknown
264
+ ** 1: same origin
265
+ ** 2: same origin + is POST
266
+ ** 3: same origin, POST, valid csrf token */
263267
264268
int parseCnt[10]; /* Counts of artifacts parsed */
265269
FILE *fDebug; /* Write debug information here, if the file exists */
266270
#ifdef FOSSIL_ENABLE_TH1_HOOKS
267271
int fNoThHook; /* Disable all TH1 command/webpage hooks */
268272
--- src/main.c
+++ src/main.c
@@ -256,12 +256,16 @@
256 /* all Tcl related context necessary for integration */
257 struct TclContext tcl;
258 #endif
259
260 /* For defense against Cross-site Request Forgery attacks */
261 char zCsrfToken[12]; /* Value of the anti-CSRF token */
262 int okCsrf; /* Anti-CSRF token is present and valid */
 
 
 
 
263
264 int parseCnt[10]; /* Counts of artifacts parsed */
265 FILE *fDebug; /* Write debug information here, if the file exists */
266 #ifdef FOSSIL_ENABLE_TH1_HOOKS
267 int fNoThHook; /* Disable all TH1 command/webpage hooks */
268
--- src/main.c
+++ src/main.c
@@ -256,12 +256,16 @@
256 /* all Tcl related context necessary for integration */
257 struct TclContext tcl;
258 #endif
259
260 /* For defense against Cross-site Request Forgery attacks */
261 char zCsrfToken[16]; /* Value of the anti-CSRF token */
262 int okCsrf; /* -1: unsafe
263 ** 0: unknown
264 ** 1: same origin
265 ** 2: same origin + is POST
266 ** 3: same origin, POST, valid csrf token */
267
268 int parseCnt[10]; /* Counts of artifacts parsed */
269 FILE *fDebug; /* Write debug information here, if the file exists */
270 #ifdef FOSSIL_ENABLE_TH1_HOOKS
271 int fNoThHook; /* Disable all TH1 command/webpage hooks */
272
+3 -5
--- src/report.c
+++ src/report.c
@@ -471,16 +471,15 @@
471471
zClrKey = trim_string(PD("k",""));
472472
zDesc = trim_string(PD("d",""));
473473
zMimetype = P("m");
474474
zTag = P("x");
475475
report_update_reportfmt_table();
476
- if( rn>0 && P("del2") ){
477
- login_verify_csrf_secret();
476
+ if( rn>0 && P("del2") && cgi_csrf_safe(2) ){
478477
db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn);
479478
cgi_redirect("reportlist");
480479
return;
481
- }else if( rn>0 && P("del1") ){
480
+ }else if( rn>0 && P("del1") && cgi_csrf_safe(2) ){
482481
zTitle = db_text(0, "SELECT title FROM reportfmt "
483482
"WHERE rn=%d", rn);
484483
if( zTitle==0 ) cgi_redirect("reportlist");
485484
486485
style_header("Are You Sure?");
@@ -514,12 +513,11 @@
514513
&& db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
515514
zTitle, rn)
516515
){
517516
zErr = mprintf("There is already another report named \"%h\"", zTitle);
518517
}
519
- if( zErr==0 ){
520
- login_verify_csrf_secret();
518
+ if( zErr==0 && cgi_csrf_safe(2) ){
521519
if( zTag && zTag[0]==0 ) zTag = 0;
522520
if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; }
523521
if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; }
524522
if( rn>0 ){
525523
db_multi_exec(
526524
--- src/report.c
+++ src/report.c
@@ -471,16 +471,15 @@
471 zClrKey = trim_string(PD("k",""));
472 zDesc = trim_string(PD("d",""));
473 zMimetype = P("m");
474 zTag = P("x");
475 report_update_reportfmt_table();
476 if( rn>0 && P("del2") ){
477 login_verify_csrf_secret();
478 db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn);
479 cgi_redirect("reportlist");
480 return;
481 }else if( rn>0 && P("del1") ){
482 zTitle = db_text(0, "SELECT title FROM reportfmt "
483 "WHERE rn=%d", rn);
484 if( zTitle==0 ) cgi_redirect("reportlist");
485
486 style_header("Are You Sure?");
@@ -514,12 +513,11 @@
514 && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
515 zTitle, rn)
516 ){
517 zErr = mprintf("There is already another report named \"%h\"", zTitle);
518 }
519 if( zErr==0 ){
520 login_verify_csrf_secret();
521 if( zTag && zTag[0]==0 ) zTag = 0;
522 if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; }
523 if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; }
524 if( rn>0 ){
525 db_multi_exec(
526
--- src/report.c
+++ src/report.c
@@ -471,16 +471,15 @@
471 zClrKey = trim_string(PD("k",""));
472 zDesc = trim_string(PD("d",""));
473 zMimetype = P("m");
474 zTag = P("x");
475 report_update_reportfmt_table();
476 if( rn>0 && P("del2") && cgi_csrf_safe(2) ){
 
477 db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn);
478 cgi_redirect("reportlist");
479 return;
480 }else if( rn>0 && P("del1") && cgi_csrf_safe(2) ){
481 zTitle = db_text(0, "SELECT title FROM reportfmt "
482 "WHERE rn=%d", rn);
483 if( zTitle==0 ) cgi_redirect("reportlist");
484
485 style_header("Are You Sure?");
@@ -514,12 +513,11 @@
513 && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
514 zTitle, rn)
515 ){
516 zErr = mprintf("There is already another report named \"%h\"", zTitle);
517 }
518 if( zErr==0 && cgi_csrf_safe(2) ){
 
519 if( zTag && zTag[0]==0 ) zTag = 0;
520 if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; }
521 if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; }
522 if( rn>0 ){
523 db_multi_exec(
524
--- src/security_audit.c
+++ src/security_audit.c
@@ -795,11 +795,11 @@
795795
@ command.
796796
@ </ol>
797797
style_finish_page();
798798
return;
799799
}
800
- if( P("truncate1") && cgi_csrf_safe(1) ){
800
+ if( P("truncate1") && cgi_csrf_safe(2) ){
801801
fclose(fopen(g.zErrlog,"w"));
802802
}
803803
if( P("download") ){
804804
Blob log;
805805
blob_read_from_file(&log, g.zErrlog, ExtFILE);
@@ -808,10 +808,11 @@
808808
return;
809809
}
810810
szFile = file_size(g.zErrlog, ExtFILE);
811811
if( P("truncate") ){
812812
@ <form action="%R/errorlog" method="POST">
813
+ login_insert_csrf_secret();
813814
@ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
814815
@ <input type="submit" name="truncate1" value="Confirm">
815816
@ <input type="submit" name="cancel" value="Cancel">
816817
@ </form>
817818
style_finish_page();
818819
--- src/security_audit.c
+++ src/security_audit.c
@@ -795,11 +795,11 @@
795 @ command.
796 @ </ol>
797 style_finish_page();
798 return;
799 }
800 if( P("truncate1") && cgi_csrf_safe(1) ){
801 fclose(fopen(g.zErrlog,"w"));
802 }
803 if( P("download") ){
804 Blob log;
805 blob_read_from_file(&log, g.zErrlog, ExtFILE);
@@ -808,10 +808,11 @@
808 return;
809 }
810 szFile = file_size(g.zErrlog, ExtFILE);
811 if( P("truncate") ){
812 @ <form action="%R/errorlog" method="POST">
 
813 @ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
814 @ <input type="submit" name="truncate1" value="Confirm">
815 @ <input type="submit" name="cancel" value="Cancel">
816 @ </form>
817 style_finish_page();
818
--- src/security_audit.c
+++ src/security_audit.c
@@ -795,11 +795,11 @@
795 @ command.
796 @ </ol>
797 style_finish_page();
798 return;
799 }
800 if( P("truncate1") && cgi_csrf_safe(2) ){
801 fclose(fopen(g.zErrlog,"w"));
802 }
803 if( P("download") ){
804 Blob log;
805 blob_read_from_file(&log, g.zErrlog, ExtFILE);
@@ -808,10 +808,11 @@
808 return;
809 }
810 szFile = file_size(g.zErrlog, ExtFILE);
811 if( P("truncate") ){
812 @ <form action="%R/errorlog" method="POST">
813 login_insert_csrf_secret();
814 @ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
815 @ <input type="submit" name="truncate1" value="Confirm">
816 @ <input type="submit" name="cancel" value="Cancel">
817 @ </form>
818 style_finish_page();
819
+12 -20
--- src/setup.c
+++ src/setup.c
@@ -202,12 +202,11 @@
202202
if( zQ==0 && !disabled && P("submit") ){
203203
zQ = "off";
204204
}
205205
if( zQ ){
206206
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
207
- if( iQ!=iVal ){
208
- login_verify_csrf_secret();
207
+ if( iQ!=iVal && cgi_csrf_safe(2) ){
209208
db_protect_only(PROTECT_NONE);
210209
db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
211210
db_protect_pop();
212211
setup_incr_cfgcnt();
213212
admin_log("Set option [%q] to [%q].",
@@ -237,13 +236,12 @@
237236
const char *zDflt, /* Default value if CONFIG table entry does not exist */
238237
int disabled /* 1 if disabled */
239238
){
240239
const char *zVal = db_get(zVar, zDflt);
241240
const char *zQ = P(zQParm);
242
- if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
241
+ if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){
243242
const int nZQ = (int)strlen(zQ);
244
- login_verify_csrf_secret();
245243
setup_incr_cfgcnt();
246244
db_protect_only(PROTECT_NONE);
247245
db_set(zVar/*works-like:"x"*/, zQ, 0);
248246
db_protect_pop();
249247
admin_log("Set entry_attribute %Q to: %.*s%s",
@@ -270,13 +268,12 @@
270268
const char *zDflt, /* Default value if CONFIG table entry does not exist */
271269
int disabled /* 1 if the textarea should not be editable */
272270
){
273271
const char *z = db_get(zVar, zDflt);
274272
const char *zQ = P(zQP);
275
- if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
273
+ if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
276274
const int nZQ = (int)strlen(zQ);
277
- login_verify_csrf_secret();
278275
db_protect_only(PROTECT_NONE);
279276
db_set(zVar/*works-like:"x"*/, zQ, 0);
280277
db_protect_pop();
281278
setup_incr_cfgcnt();
282279
admin_log("Set textarea_attribute %Q to: %.*s%s",
@@ -309,13 +306,12 @@
309306
const char *const *azChoice /* Choices in pairs (VAR value, Display) */
310307
){
311308
const char *z = db_get(zVar, zDflt);
312309
const char *zQ = P(zQP);
313310
int i;
314
- if( zQ && fossil_strcmp(zQ,z)!=0){
311
+ if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
315312
const int nZQ = (int)strlen(zQ);
316
- login_verify_csrf_secret();
317313
db_unprotect(PROTECT_ALL);
318314
db_set(zVar/*works-like:"x"*/, zQ, 0);
319315
setup_incr_cfgcnt();
320316
db_protect_pop();
321317
admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
@@ -1458,11 +1454,11 @@
14581454
if( !g.perm.Admin ){
14591455
login_needed(0);
14601456
return;
14611457
}
14621458
db_begin_transaction();
1463
- if( P("clear")!=0 && cgi_csrf_safe(1) ){
1459
+ if( P("clear")!=0 && cgi_csrf_safe(2) ){
14641460
db_unprotect(PROTECT_CONFIG);
14651461
db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
14661462
db_protect_pop();
14671463
cgi_replace_parameter("adunit","");
14681464
cgi_replace_parameter("adright","");
@@ -1560,11 +1556,11 @@
15601556
if( !g.perm.Admin ){
15611557
login_needed(0);
15621558
return;
15631559
}
15641560
db_begin_transaction();
1565
- if( !cgi_csrf_safe(1) ){
1561
+ if( !cgi_csrf_safe(2) ){
15661562
/* Allow no state changes if not safe from CSRF */
15671563
}else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
15681564
Blob img;
15691565
Stmt ins;
15701566
blob_init(&img, aLogoImg, szLogoImg);
@@ -1769,11 +1765,11 @@
17691765
if( !g.perm.Setup ){
17701766
login_needed(0);
17711767
return;
17721768
}
17731769
add_content_sql_commands(g.db);
1774
- zQ = cgi_csrf_safe(1) ? P("q") : 0;
1770
+ zQ = cgi_csrf_safe(2) ? P("q") : 0;
17751771
style_set_current_feature("setup");
17761772
style_header("Raw SQL Commands");
17771773
@ <p><b>Caution:</b> There are no restrictions on the SQL that can be
17781774
@ run by this page. You can do serious and irrepairable damage to the
17791775
@ repository. Proceed with extreme caution.</p>
@@ -1822,19 +1818,18 @@
18221818
go = 1;
18231819
}else if( P("tablelist") ){
18241820
zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name");
18251821
go = 1;
18261822
}
1827
- if( go ){
1823
+ if( go && cgi_csrf_safe(2) ){
18281824
sqlite3_stmt *pStmt;
18291825
int rc;
18301826
const char *zTail;
18311827
int nCol;
18321828
int nRow = 0;
18331829
int i;
18341830
@ <hr>
1835
- login_verify_csrf_secret();
18361831
sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0);
18371832
search_sql_setup(g.db);
18381833
rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail);
18391834
if( rc!=SQLITE_OK ){
18401835
@ <div class="generalError">%h(sqlite3_errmsg(g.db))</div>
@@ -1913,22 +1908,20 @@
19131908
style_header("Raw TH1 Commands");
19141909
@ <p><b>Caution:</b> There are no restrictions on the TH1 that can be
19151910
@ run by this page. If Tcl integration was enabled at compile-time and
19161911
@ the "tcl" setting is enabled, Tcl commands may be run as well.</p>
19171912
@
1918
- @ <form method="post" action="%R/admin_th1">
1919
- login_insert_csrf_secret();
1913
+ form_begin(0, "%R/admin_th1");
19201914
@ TH1:<br>
19211915
@ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br>
19221916
@ <input type="submit" name="go" value="Run TH1">
19231917
@ </form>
1924
- if( go ){
1918
+ if( go && cgi_csrf_safe(2) ){
19251919
const char *zR;
19261920
int rc;
19271921
int n;
19281922
@ <hr>
1929
- login_verify_csrf_secret();
19301923
rc = Th_Eval(g.interp, 0, zQ, -1);
19311924
zR = Th_GetResult(g.interp, &n);
19321925
if( rc==TH_OK ){
19331926
@ <pre class="th1result">%h(zR)</pre>
19341927
}else{
@@ -2129,11 +2122,11 @@
21292122
Blob *pSql,
21302123
const char *zOldName,
21312124
const char *zNewName,
21322125
const char *zValue
21332126
){
2134
- if( !cgi_csrf_safe(1) ) return;
2127
+ if( !cgi_csrf_safe(2) ) return;
21352128
if( zNewName[0]==0 || zValue[0]==0 ){
21362129
if( zOldName[0] ){
21372130
blob_append_sql(pSql,
21382131
"DELETE FROM config WHERE name='walias:%q';\n",
21392132
zOldName);
@@ -2173,17 +2166,16 @@
21732166
login_needed(0);
21742167
return;
21752168
}
21762169
style_set_current_feature("setup");
21772170
style_header("URL Alias Configuration");
2178
- if( P("submit")!=0 ){
2171
+ if( P("submit")!=0 && cgi_csrf_safe(2) ){
21792172
Blob token;
21802173
Blob sql;
21812174
const char *zNewName;
21822175
const char *zValue;
21832176
char zCnt[10];
2184
- login_verify_csrf_secret();
21852177
blob_init(&namelist, PD("namelist",""), -1);
21862178
blob_init(&sql, 0, 0);
21872179
while( blob_token(&namelist, &token) ){
21882180
const char *zOldName = blob_str(&token);
21892181
sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
21902182
--- src/setup.c
+++ src/setup.c
@@ -202,12 +202,11 @@
202 if( zQ==0 && !disabled && P("submit") ){
203 zQ = "off";
204 }
205 if( zQ ){
206 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
207 if( iQ!=iVal ){
208 login_verify_csrf_secret();
209 db_protect_only(PROTECT_NONE);
210 db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
211 db_protect_pop();
212 setup_incr_cfgcnt();
213 admin_log("Set option [%q] to [%q].",
@@ -237,13 +236,12 @@
237 const char *zDflt, /* Default value if CONFIG table entry does not exist */
238 int disabled /* 1 if disabled */
239 ){
240 const char *zVal = db_get(zVar, zDflt);
241 const char *zQ = P(zQParm);
242 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
243 const int nZQ = (int)strlen(zQ);
244 login_verify_csrf_secret();
245 setup_incr_cfgcnt();
246 db_protect_only(PROTECT_NONE);
247 db_set(zVar/*works-like:"x"*/, zQ, 0);
248 db_protect_pop();
249 admin_log("Set entry_attribute %Q to: %.*s%s",
@@ -270,13 +268,12 @@
270 const char *zDflt, /* Default value if CONFIG table entry does not exist */
271 int disabled /* 1 if the textarea should not be editable */
272 ){
273 const char *z = db_get(zVar, zDflt);
274 const char *zQ = P(zQP);
275 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
276 const int nZQ = (int)strlen(zQ);
277 login_verify_csrf_secret();
278 db_protect_only(PROTECT_NONE);
279 db_set(zVar/*works-like:"x"*/, zQ, 0);
280 db_protect_pop();
281 setup_incr_cfgcnt();
282 admin_log("Set textarea_attribute %Q to: %.*s%s",
@@ -309,13 +306,12 @@
309 const char *const *azChoice /* Choices in pairs (VAR value, Display) */
310 ){
311 const char *z = db_get(zVar, zDflt);
312 const char *zQ = P(zQP);
313 int i;
314 if( zQ && fossil_strcmp(zQ,z)!=0){
315 const int nZQ = (int)strlen(zQ);
316 login_verify_csrf_secret();
317 db_unprotect(PROTECT_ALL);
318 db_set(zVar/*works-like:"x"*/, zQ, 0);
319 setup_incr_cfgcnt();
320 db_protect_pop();
321 admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
@@ -1458,11 +1454,11 @@
1458 if( !g.perm.Admin ){
1459 login_needed(0);
1460 return;
1461 }
1462 db_begin_transaction();
1463 if( P("clear")!=0 && cgi_csrf_safe(1) ){
1464 db_unprotect(PROTECT_CONFIG);
1465 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
1466 db_protect_pop();
1467 cgi_replace_parameter("adunit","");
1468 cgi_replace_parameter("adright","");
@@ -1560,11 +1556,11 @@
1560 if( !g.perm.Admin ){
1561 login_needed(0);
1562 return;
1563 }
1564 db_begin_transaction();
1565 if( !cgi_csrf_safe(1) ){
1566 /* Allow no state changes if not safe from CSRF */
1567 }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
1568 Blob img;
1569 Stmt ins;
1570 blob_init(&img, aLogoImg, szLogoImg);
@@ -1769,11 +1765,11 @@
1769 if( !g.perm.Setup ){
1770 login_needed(0);
1771 return;
1772 }
1773 add_content_sql_commands(g.db);
1774 zQ = cgi_csrf_safe(1) ? P("q") : 0;
1775 style_set_current_feature("setup");
1776 style_header("Raw SQL Commands");
1777 @ <p><b>Caution:</b> There are no restrictions on the SQL that can be
1778 @ run by this page. You can do serious and irrepairable damage to the
1779 @ repository. Proceed with extreme caution.</p>
@@ -1822,19 +1818,18 @@
1822 go = 1;
1823 }else if( P("tablelist") ){
1824 zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name");
1825 go = 1;
1826 }
1827 if( go ){
1828 sqlite3_stmt *pStmt;
1829 int rc;
1830 const char *zTail;
1831 int nCol;
1832 int nRow = 0;
1833 int i;
1834 @ <hr>
1835 login_verify_csrf_secret();
1836 sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0);
1837 search_sql_setup(g.db);
1838 rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail);
1839 if( rc!=SQLITE_OK ){
1840 @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div>
@@ -1913,22 +1908,20 @@
1913 style_header("Raw TH1 Commands");
1914 @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be
1915 @ run by this page. If Tcl integration was enabled at compile-time and
1916 @ the "tcl" setting is enabled, Tcl commands may be run as well.</p>
1917 @
1918 @ <form method="post" action="%R/admin_th1">
1919 login_insert_csrf_secret();
1920 @ TH1:<br>
1921 @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br>
1922 @ <input type="submit" name="go" value="Run TH1">
1923 @ </form>
1924 if( go ){
1925 const char *zR;
1926 int rc;
1927 int n;
1928 @ <hr>
1929 login_verify_csrf_secret();
1930 rc = Th_Eval(g.interp, 0, zQ, -1);
1931 zR = Th_GetResult(g.interp, &n);
1932 if( rc==TH_OK ){
1933 @ <pre class="th1result">%h(zR)</pre>
1934 }else{
@@ -2129,11 +2122,11 @@
2129 Blob *pSql,
2130 const char *zOldName,
2131 const char *zNewName,
2132 const char *zValue
2133 ){
2134 if( !cgi_csrf_safe(1) ) return;
2135 if( zNewName[0]==0 || zValue[0]==0 ){
2136 if( zOldName[0] ){
2137 blob_append_sql(pSql,
2138 "DELETE FROM config WHERE name='walias:%q';\n",
2139 zOldName);
@@ -2173,17 +2166,16 @@
2173 login_needed(0);
2174 return;
2175 }
2176 style_set_current_feature("setup");
2177 style_header("URL Alias Configuration");
2178 if( P("submit")!=0 ){
2179 Blob token;
2180 Blob sql;
2181 const char *zNewName;
2182 const char *zValue;
2183 char zCnt[10];
2184 login_verify_csrf_secret();
2185 blob_init(&namelist, PD("namelist",""), -1);
2186 blob_init(&sql, 0, 0);
2187 while( blob_token(&namelist, &token) ){
2188 const char *zOldName = blob_str(&token);
2189 sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
2190
--- src/setup.c
+++ src/setup.c
@@ -202,12 +202,11 @@
202 if( zQ==0 && !disabled && P("submit") ){
203 zQ = "off";
204 }
205 if( zQ ){
206 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
207 if( iQ!=iVal && cgi_csrf_safe(2) ){
 
208 db_protect_only(PROTECT_NONE);
209 db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
210 db_protect_pop();
211 setup_incr_cfgcnt();
212 admin_log("Set option [%q] to [%q].",
@@ -237,13 +236,12 @@
236 const char *zDflt, /* Default value if CONFIG table entry does not exist */
237 int disabled /* 1 if disabled */
238 ){
239 const char *zVal = db_get(zVar, zDflt);
240 const char *zQ = P(zQParm);
241 if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){
242 const int nZQ = (int)strlen(zQ);
 
243 setup_incr_cfgcnt();
244 db_protect_only(PROTECT_NONE);
245 db_set(zVar/*works-like:"x"*/, zQ, 0);
246 db_protect_pop();
247 admin_log("Set entry_attribute %Q to: %.*s%s",
@@ -270,13 +268,12 @@
268 const char *zDflt, /* Default value if CONFIG table entry does not exist */
269 int disabled /* 1 if the textarea should not be editable */
270 ){
271 const char *z = db_get(zVar, zDflt);
272 const char *zQ = P(zQP);
273 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
274 const int nZQ = (int)strlen(zQ);
 
275 db_protect_only(PROTECT_NONE);
276 db_set(zVar/*works-like:"x"*/, zQ, 0);
277 db_protect_pop();
278 setup_incr_cfgcnt();
279 admin_log("Set textarea_attribute %Q to: %.*s%s",
@@ -309,13 +306,12 @@
306 const char *const *azChoice /* Choices in pairs (VAR value, Display) */
307 ){
308 const char *z = db_get(zVar, zDflt);
309 const char *zQ = P(zQP);
310 int i;
311 if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
312 const int nZQ = (int)strlen(zQ);
 
313 db_unprotect(PROTECT_ALL);
314 db_set(zVar/*works-like:"x"*/, zQ, 0);
315 setup_incr_cfgcnt();
316 db_protect_pop();
317 admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
@@ -1458,11 +1454,11 @@
1454 if( !g.perm.Admin ){
1455 login_needed(0);
1456 return;
1457 }
1458 db_begin_transaction();
1459 if( P("clear")!=0 && cgi_csrf_safe(2) ){
1460 db_unprotect(PROTECT_CONFIG);
1461 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
1462 db_protect_pop();
1463 cgi_replace_parameter("adunit","");
1464 cgi_replace_parameter("adright","");
@@ -1560,11 +1556,11 @@
1556 if( !g.perm.Admin ){
1557 login_needed(0);
1558 return;
1559 }
1560 db_begin_transaction();
1561 if( !cgi_csrf_safe(2) ){
1562 /* Allow no state changes if not safe from CSRF */
1563 }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
1564 Blob img;
1565 Stmt ins;
1566 blob_init(&img, aLogoImg, szLogoImg);
@@ -1769,11 +1765,11 @@
1765 if( !g.perm.Setup ){
1766 login_needed(0);
1767 return;
1768 }
1769 add_content_sql_commands(g.db);
1770 zQ = cgi_csrf_safe(2) ? P("q") : 0;
1771 style_set_current_feature("setup");
1772 style_header("Raw SQL Commands");
1773 @ <p><b>Caution:</b> There are no restrictions on the SQL that can be
1774 @ run by this page. You can do serious and irrepairable damage to the
1775 @ repository. Proceed with extreme caution.</p>
@@ -1822,19 +1818,18 @@
1818 go = 1;
1819 }else if( P("tablelist") ){
1820 zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name");
1821 go = 1;
1822 }
1823 if( go && cgi_csrf_safe(2) ){
1824 sqlite3_stmt *pStmt;
1825 int rc;
1826 const char *zTail;
1827 int nCol;
1828 int nRow = 0;
1829 int i;
1830 @ <hr>
 
1831 sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0);
1832 search_sql_setup(g.db);
1833 rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail);
1834 if( rc!=SQLITE_OK ){
1835 @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div>
@@ -1913,22 +1908,20 @@
1908 style_header("Raw TH1 Commands");
1909 @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be
1910 @ run by this page. If Tcl integration was enabled at compile-time and
1911 @ the "tcl" setting is enabled, Tcl commands may be run as well.</p>
1912 @
1913 form_begin(0, "%R/admin_th1");
 
1914 @ TH1:<br>
1915 @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br>
1916 @ <input type="submit" name="go" value="Run TH1">
1917 @ </form>
1918 if( go && cgi_csrf_safe(2) ){
1919 const char *zR;
1920 int rc;
1921 int n;
1922 @ <hr>
 
1923 rc = Th_Eval(g.interp, 0, zQ, -1);
1924 zR = Th_GetResult(g.interp, &n);
1925 if( rc==TH_OK ){
1926 @ <pre class="th1result">%h(zR)</pre>
1927 }else{
@@ -2129,11 +2122,11 @@
2122 Blob *pSql,
2123 const char *zOldName,
2124 const char *zNewName,
2125 const char *zValue
2126 ){
2127 if( !cgi_csrf_safe(2) ) return;
2128 if( zNewName[0]==0 || zValue[0]==0 ){
2129 if( zOldName[0] ){
2130 blob_append_sql(pSql,
2131 "DELETE FROM config WHERE name='walias:%q';\n",
2132 zOldName);
@@ -2173,17 +2166,16 @@
2166 login_needed(0);
2167 return;
2168 }
2169 style_set_current_feature("setup");
2170 style_header("URL Alias Configuration");
2171 if( P("submit")!=0 && cgi_csrf_safe(2) ){
2172 Blob token;
2173 Blob sql;
2174 const char *zNewName;
2175 const char *zValue;
2176 char zCnt[10];
 
2177 blob_init(&namelist, PD("namelist",""), -1);
2178 blob_init(&sql, 0, 0);
2179 while( blob_token(&namelist, &token) ){
2180 const char *zOldName = blob_str(&token);
2181 sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
2182
+3 -3
--- src/setupuser.c
+++ src/setupuser.c
@@ -342,11 +342,11 @@
342342
cgi_redirect(cgi_referer("setup_ulist"));
343343
return;
344344
}
345345
346346
/* Check for requests to delete the user */
347
- if( P("delete") && cgi_csrf_safe(1) ){
347
+ if( P("delete") && cgi_csrf_safe(2) ){
348348
int n;
349349
if( P("verifydelete") ){
350350
/* Verified delete user request */
351351
db_unprotect(PROTECT_USER);
352352
if( alert_tables_exist() ){
@@ -386,11 +386,11 @@
386386
** more are missing, no-op */
387387
}else if( higherUser ){
388388
/* An Admin (a) user cannot edit a Superuser (s) */
389389
}else if( zDeleteVerify!=0 ){
390390
/* Need to verify a delete request */
391
- }else if( !cgi_csrf_safe(1) ){
391
+ }else if( !cgi_csrf_safe(2) ){
392392
/* This might be a cross-site request forgery, so ignore it */
393393
}else{
394394
/* We have all the information we need to make the change to the user */
395395
char c;
396396
char zCap[70], zNm[4];
@@ -440,11 +440,11 @@
440440
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
441441
@ [Bummer]</a></p>
442442
style_finish_page();
443443
return;
444444
}
445
- login_verify_csrf_secret();
445
+ cgi_csrf_verify();
446446
db_unprotect(PROTECT_USER);
447447
db_multi_exec(
448448
"REPLACE INTO user(uid,login,info,pw,cap,mtime) "
449449
"VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
450450
uid, zLogin, P("info"), zPw, zCap
451451
--- src/setupuser.c
+++ src/setupuser.c
@@ -342,11 +342,11 @@
342 cgi_redirect(cgi_referer("setup_ulist"));
343 return;
344 }
345
346 /* Check for requests to delete the user */
347 if( P("delete") && cgi_csrf_safe(1) ){
348 int n;
349 if( P("verifydelete") ){
350 /* Verified delete user request */
351 db_unprotect(PROTECT_USER);
352 if( alert_tables_exist() ){
@@ -386,11 +386,11 @@
386 ** more are missing, no-op */
387 }else if( higherUser ){
388 /* An Admin (a) user cannot edit a Superuser (s) */
389 }else if( zDeleteVerify!=0 ){
390 /* Need to verify a delete request */
391 }else if( !cgi_csrf_safe(1) ){
392 /* This might be a cross-site request forgery, so ignore it */
393 }else{
394 /* We have all the information we need to make the change to the user */
395 char c;
396 char zCap[70], zNm[4];
@@ -440,11 +440,11 @@
440 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
441 @ [Bummer]</a></p>
442 style_finish_page();
443 return;
444 }
445 login_verify_csrf_secret();
446 db_unprotect(PROTECT_USER);
447 db_multi_exec(
448 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
449 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
450 uid, zLogin, P("info"), zPw, zCap
451
--- src/setupuser.c
+++ src/setupuser.c
@@ -342,11 +342,11 @@
342 cgi_redirect(cgi_referer("setup_ulist"));
343 return;
344 }
345
346 /* Check for requests to delete the user */
347 if( P("delete") && cgi_csrf_safe(2) ){
348 int n;
349 if( P("verifydelete") ){
350 /* Verified delete user request */
351 db_unprotect(PROTECT_USER);
352 if( alert_tables_exist() ){
@@ -386,11 +386,11 @@
386 ** more are missing, no-op */
387 }else if( higherUser ){
388 /* An Admin (a) user cannot edit a Superuser (s) */
389 }else if( zDeleteVerify!=0 ){
390 /* Need to verify a delete request */
391 }else if( !cgi_csrf_safe(2) ){
392 /* This might be a cross-site request forgery, so ignore it */
393 }else{
394 /* We have all the information we need to make the change to the user */
395 char c;
396 char zCap[70], zNm[4];
@@ -440,11 +440,11 @@
440 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
441 @ [Bummer]</a></p>
442 style_finish_page();
443 return;
444 }
445 cgi_csrf_verify();
446 db_unprotect(PROTECT_USER);
447 db_multi_exec(
448 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
449 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
450 uid, zLogin, P("info"), zPw, zCap
451
+13
--- src/sha1.c
+++ src/sha1.c
@@ -392,10 +392,23 @@
392392
blob_resize(pCksum, 40);
393393
SHA1Final(zResult, &ctx);
394394
DigestToBase16(zResult, blob_buffer(pCksum));
395395
return 0;
396396
}
397
+
398
+/*
399
+** Compute a binary SHA1 checksum of a zero-terminated string. The
400
+** result is stored in zOut, which is a buffer that must be at least
401
+** 20 bytes in size.
402
+*/
403
+void sha1sum_binary(const char *zIn, unsigned char *zOut){
404
+ SHA1Context ctx;
405
+
406
+ SHA1Init(&ctx);
407
+ SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
408
+ SHA1Final(zOut, &ctx);
409
+}
397410
398411
/*
399412
** Compute the SHA1 checksum of a zero-terminated string. The
400413
** result is held in memory obtained from mprintf().
401414
*/
402415
--- src/sha1.c
+++ src/sha1.c
@@ -392,10 +392,23 @@
392 blob_resize(pCksum, 40);
393 SHA1Final(zResult, &ctx);
394 DigestToBase16(zResult, blob_buffer(pCksum));
395 return 0;
396 }
 
 
 
 
 
 
 
 
 
 
 
 
 
397
398 /*
399 ** Compute the SHA1 checksum of a zero-terminated string. The
400 ** result is held in memory obtained from mprintf().
401 */
402
--- src/sha1.c
+++ src/sha1.c
@@ -392,10 +392,23 @@
392 blob_resize(pCksum, 40);
393 SHA1Final(zResult, &ctx);
394 DigestToBase16(zResult, blob_buffer(pCksum));
395 return 0;
396 }
397
398 /*
399 ** Compute a binary SHA1 checksum of a zero-terminated string. The
400 ** result is stored in zOut, which is a buffer that must be at least
401 ** 20 bytes in size.
402 */
403 void sha1sum_binary(const char *zIn, unsigned char *zOut){
404 SHA1Context ctx;
405
406 SHA1Init(&ctx);
407 SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
408 SHA1Final(zOut, &ctx);
409 }
410
411 /*
412 ** Compute the SHA1 checksum of a zero-terminated string. The
413 ** result is held in memory obtained from mprintf().
414 */
415
+2 -4
--- src/shun.c
+++ src/shun.c
@@ -98,14 +98,13 @@
9898
}
9999
}
100100
zUuid = zCanonical;
101101
}
102102
style_header("Shunned Artifacts");
103
- if( zUuid && P("sub") ){
103
+ if( zUuid && P("sub") && cgi_csrf_safe(2) ){
104104
const char *p = zUuid;
105105
int allExist = 1;
106
- login_verify_csrf_secret();
107106
while( *p ){
108107
db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
109108
if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
110109
allExist = 0;
111110
}
@@ -127,14 +126,13 @@
127126
@ It may be necessary to rebuild the repository using the
128127
@ <b>fossil rebuild</b> command-line before the artifact content
129128
@ can pulled in from other repositories.</p>
130129
}
131130
}
132
- if( zUuid && P("add") ){
131
+ if( zUuid && P("add") && cgi_csrf_safe(2) ){
133132
const char *p = zUuid;
134133
int rid, tagid;
135
- login_verify_csrf_secret();
136134
while( *p ){
137135
db_multi_exec(
138136
"INSERT OR IGNORE INTO shun(uuid,mtime)"
139137
" VALUES(%Q, now())", p);
140138
db_multi_exec("DELETE FROM attachment WHERE src=%Q", p);
141139
--- src/shun.c
+++ src/shun.c
@@ -98,14 +98,13 @@
98 }
99 }
100 zUuid = zCanonical;
101 }
102 style_header("Shunned Artifacts");
103 if( zUuid && P("sub") ){
104 const char *p = zUuid;
105 int allExist = 1;
106 login_verify_csrf_secret();
107 while( *p ){
108 db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
109 if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
110 allExist = 0;
111 }
@@ -127,14 +126,13 @@
127 @ It may be necessary to rebuild the repository using the
128 @ <b>fossil rebuild</b> command-line before the artifact content
129 @ can pulled in from other repositories.</p>
130 }
131 }
132 if( zUuid && P("add") ){
133 const char *p = zUuid;
134 int rid, tagid;
135 login_verify_csrf_secret();
136 while( *p ){
137 db_multi_exec(
138 "INSERT OR IGNORE INTO shun(uuid,mtime)"
139 " VALUES(%Q, now())", p);
140 db_multi_exec("DELETE FROM attachment WHERE src=%Q", p);
141
--- src/shun.c
+++ src/shun.c
@@ -98,14 +98,13 @@
98 }
99 }
100 zUuid = zCanonical;
101 }
102 style_header("Shunned Artifacts");
103 if( zUuid && P("sub") && cgi_csrf_safe(2) ){
104 const char *p = zUuid;
105 int allExist = 1;
 
106 while( *p ){
107 db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
108 if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
109 allExist = 0;
110 }
@@ -127,14 +126,13 @@
126 @ It may be necessary to rebuild the repository using the
127 @ <b>fossil rebuild</b> command-line before the artifact content
128 @ can pulled in from other repositories.</p>
129 }
130 }
131 if( zUuid && P("add") && cgi_csrf_safe(2) ){
132 const char *p = zUuid;
133 int rid, tagid;
 
134 while( *p ){
135 db_multi_exec(
136 "INSERT OR IGNORE INTO shun(uuid,mtime)"
137 " VALUES(%Q, now())", p);
138 db_multi_exec("DELETE FROM attachment WHERE src=%Q", p);
139
+10 -3
--- src/skins.c
+++ src/skins.c
@@ -531,11 +531,11 @@
531531
aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
532532
}
533533
534534
style_set_current_feature("skins");
535535
536
- if( cgi_csrf_safe(1) ){
536
+ if( cgi_csrf_safe(2) ){
537537
/* Process requests to delete a user-defined skin */
538538
if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
539539
style_header("Confirm Custom Skin Delete");
540540
@ <form action="%R/setup_skin_admin" method="post"><div>
541541
@ <p>Deletion of a custom skin is a permanent action that cannot
@@ -628,10 +628,11 @@
628628
seenCurrent = 1;
629629
}else{
630630
@ <form action="%R/setup_skin_admin" method="post">
631631
@ <input type="hidden" name="sn" value="%h(z)">
632632
@ <input type="submit" name="load" value="Install">
633
+ login_insert_csrf_secret();
633634
if( pAltSkin==&aBuiltinSkin[i] ){
634635
@ (Current override)
635636
}
636637
@ </form>
637638
}
@@ -652,10 +653,11 @@
652653
@ <tr><td colspan=4><h2>Skins saved as "skin:*' entries \
653654
@ in the CONFIG table:</h2></td></tr>
654655
}
655656
@ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
656657
@ <form action="%R/setup_skin_admin" method="post">
658
+ login_insert_csrf_secret();
657659
if( fossil_strcmp(zV, zCurrent)==0 ){
658660
@ (Currently In Use)
659661
seenCurrent = 1;
660662
}else{
661663
@ <input type="submit" name="load" value="Install">
@@ -671,10 +673,11 @@
671673
@ <tr><td colspan=4><h2>Current skin in css/header/footer/details entries \
672674
@ in the CONFIG table:</h2></td></tr>
673675
@ <tr><td>%d(i).<td><i>Current</i><td>&nbsp;&nbsp;<td>
674676
@ <form action="%R/setup_skin_admin" method="post">
675677
@ <input type="submit" name="save" value="Backup">
678
+ login_insert_csrf_secret();
676679
@ </form>
677680
}
678681
db_prepare(&q,
679682
"SELECT DISTINCT substr(name, 1, 6) FROM config"
680683
" WHERE name GLOB 'draft[1-9]-*'"
@@ -689,10 +692,11 @@
689692
@ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \
690693
@ in the CONFIG table:</h2></td></tr>
691694
}
692695
@ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
693696
@ <form action="%R/setup_skin_admin" method="post">
697
+ login_insert_csrf_secret();
694698
@ <input type="submit" name="draftdel" value="Delete">
695699
@ <input type="hidden" name="name" value="%h(zN)">
696700
@ </form></tr>
697701
}
698702
db_finalize(&q);
@@ -836,11 +840,11 @@
836840
zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
837841
zBasis = PD("basis","current");
838842
zDflt = skin_file_content(zBasis, zFile);
839843
zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
840844
zContent = PD(zFile,zOrig);
841
- if( P("revert")!=0 && cgi_csrf_safe(0) ){
845
+ if( P("revert")!=0 && cgi_csrf_safe(2) ){
842846
zContent = zDflt;
843847
isRevert = 1;
844848
}
845849
846850
db_begin_transaction();
@@ -853,11 +857,13 @@
853857
@ <form action="%R/setup_skinedit" method="post"><div>
854858
login_insert_csrf_secret();
855859
@ <input type='hidden' name='w' value='%d(ii)'>
856860
@ <input type='hidden' name='sk' value='%d(iSkin)'>
857861
@ <h2>Edit %s(zTitle):</h2>
858
- if( P("submit") && cgi_csrf_safe(0) && (zOrig==0 || strcmp(zOrig,zContent)!=0) ){
862
+ if( P("submit") && cgi_csrf_safe(2)
863
+ && (zOrig==0 || strcmp(zOrig,zContent)!=0)
864
+ ){
859865
db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
860866
}
861867
@ <textarea name="%s(zFile)" rows="10" cols="80">\
862868
@ %h(zContent)</textarea>
863869
@ <br>
@@ -1042,10 +1048,11 @@
10421048
@ <option value='%d(i)'>draft%d(i)</option>
10431049
}
10441050
}
10451051
@ </select>
10461052
@ </p>
1053
+ @ </form>
10471054
@
10481055
@ <a name='step2'></a>
10491056
@ <h1>Step 2: Authenticate</h1>
10501057
@
10511058
if( isSetup ){
10521059
--- src/skins.c
+++ src/skins.c
@@ -531,11 +531,11 @@
531 aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
532 }
533
534 style_set_current_feature("skins");
535
536 if( cgi_csrf_safe(1) ){
537 /* Process requests to delete a user-defined skin */
538 if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
539 style_header("Confirm Custom Skin Delete");
540 @ <form action="%R/setup_skin_admin" method="post"><div>
541 @ <p>Deletion of a custom skin is a permanent action that cannot
@@ -628,10 +628,11 @@
628 seenCurrent = 1;
629 }else{
630 @ <form action="%R/setup_skin_admin" method="post">
631 @ <input type="hidden" name="sn" value="%h(z)">
632 @ <input type="submit" name="load" value="Install">
 
633 if( pAltSkin==&aBuiltinSkin[i] ){
634 @ (Current override)
635 }
636 @ </form>
637 }
@@ -652,10 +653,11 @@
652 @ <tr><td colspan=4><h2>Skins saved as "skin:*' entries \
653 @ in the CONFIG table:</h2></td></tr>
654 }
655 @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
656 @ <form action="%R/setup_skin_admin" method="post">
 
657 if( fossil_strcmp(zV, zCurrent)==0 ){
658 @ (Currently In Use)
659 seenCurrent = 1;
660 }else{
661 @ <input type="submit" name="load" value="Install">
@@ -671,10 +673,11 @@
671 @ <tr><td colspan=4><h2>Current skin in css/header/footer/details entries \
672 @ in the CONFIG table:</h2></td></tr>
673 @ <tr><td>%d(i).<td><i>Current</i><td>&nbsp;&nbsp;<td>
674 @ <form action="%R/setup_skin_admin" method="post">
675 @ <input type="submit" name="save" value="Backup">
 
676 @ </form>
677 }
678 db_prepare(&q,
679 "SELECT DISTINCT substr(name, 1, 6) FROM config"
680 " WHERE name GLOB 'draft[1-9]-*'"
@@ -689,10 +692,11 @@
689 @ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \
690 @ in the CONFIG table:</h2></td></tr>
691 }
692 @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
693 @ <form action="%R/setup_skin_admin" method="post">
 
694 @ <input type="submit" name="draftdel" value="Delete">
695 @ <input type="hidden" name="name" value="%h(zN)">
696 @ </form></tr>
697 }
698 db_finalize(&q);
@@ -836,11 +840,11 @@
836 zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
837 zBasis = PD("basis","current");
838 zDflt = skin_file_content(zBasis, zFile);
839 zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
840 zContent = PD(zFile,zOrig);
841 if( P("revert")!=0 && cgi_csrf_safe(0) ){
842 zContent = zDflt;
843 isRevert = 1;
844 }
845
846 db_begin_transaction();
@@ -853,11 +857,13 @@
853 @ <form action="%R/setup_skinedit" method="post"><div>
854 login_insert_csrf_secret();
855 @ <input type='hidden' name='w' value='%d(ii)'>
856 @ <input type='hidden' name='sk' value='%d(iSkin)'>
857 @ <h2>Edit %s(zTitle):</h2>
858 if( P("submit") && cgi_csrf_safe(0) && (zOrig==0 || strcmp(zOrig,zContent)!=0) ){
 
 
859 db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
860 }
861 @ <textarea name="%s(zFile)" rows="10" cols="80">\
862 @ %h(zContent)</textarea>
863 @ <br>
@@ -1042,10 +1048,11 @@
1042 @ <option value='%d(i)'>draft%d(i)</option>
1043 }
1044 }
1045 @ </select>
1046 @ </p>
 
1047 @
1048 @ <a name='step2'></a>
1049 @ <h1>Step 2: Authenticate</h1>
1050 @
1051 if( isSetup ){
1052
--- src/skins.c
+++ src/skins.c
@@ -531,11 +531,11 @@
531 aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
532 }
533
534 style_set_current_feature("skins");
535
536 if( cgi_csrf_safe(2) ){
537 /* Process requests to delete a user-defined skin */
538 if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
539 style_header("Confirm Custom Skin Delete");
540 @ <form action="%R/setup_skin_admin" method="post"><div>
541 @ <p>Deletion of a custom skin is a permanent action that cannot
@@ -628,10 +628,11 @@
628 seenCurrent = 1;
629 }else{
630 @ <form action="%R/setup_skin_admin" method="post">
631 @ <input type="hidden" name="sn" value="%h(z)">
632 @ <input type="submit" name="load" value="Install">
633 login_insert_csrf_secret();
634 if( pAltSkin==&aBuiltinSkin[i] ){
635 @ (Current override)
636 }
637 @ </form>
638 }
@@ -652,10 +653,11 @@
653 @ <tr><td colspan=4><h2>Skins saved as "skin:*' entries \
654 @ in the CONFIG table:</h2></td></tr>
655 }
656 @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
657 @ <form action="%R/setup_skin_admin" method="post">
658 login_insert_csrf_secret();
659 if( fossil_strcmp(zV, zCurrent)==0 ){
660 @ (Currently In Use)
661 seenCurrent = 1;
662 }else{
663 @ <input type="submit" name="load" value="Install">
@@ -671,10 +673,11 @@
673 @ <tr><td colspan=4><h2>Current skin in css/header/footer/details entries \
674 @ in the CONFIG table:</h2></td></tr>
675 @ <tr><td>%d(i).<td><i>Current</i><td>&nbsp;&nbsp;<td>
676 @ <form action="%R/setup_skin_admin" method="post">
677 @ <input type="submit" name="save" value="Backup">
678 login_insert_csrf_secret();
679 @ </form>
680 }
681 db_prepare(&q,
682 "SELECT DISTINCT substr(name, 1, 6) FROM config"
683 " WHERE name GLOB 'draft[1-9]-*'"
@@ -689,10 +692,11 @@
692 @ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \
693 @ in the CONFIG table:</h2></td></tr>
694 }
695 @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
696 @ <form action="%R/setup_skin_admin" method="post">
697 login_insert_csrf_secret();
698 @ <input type="submit" name="draftdel" value="Delete">
699 @ <input type="hidden" name="name" value="%h(zN)">
700 @ </form></tr>
701 }
702 db_finalize(&q);
@@ -836,11 +840,11 @@
840 zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
841 zBasis = PD("basis","current");
842 zDflt = skin_file_content(zBasis, zFile);
843 zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
844 zContent = PD(zFile,zOrig);
845 if( P("revert")!=0 && cgi_csrf_safe(2) ){
846 zContent = zDflt;
847 isRevert = 1;
848 }
849
850 db_begin_transaction();
@@ -853,11 +857,13 @@
857 @ <form action="%R/setup_skinedit" method="post"><div>
858 login_insert_csrf_secret();
859 @ <input type='hidden' name='w' value='%d(ii)'>
860 @ <input type='hidden' name='sk' value='%d(iSkin)'>
861 @ <h2>Edit %s(zTitle):</h2>
862 if( P("submit") && cgi_csrf_safe(2)
863 && (zOrig==0 || strcmp(zOrig,zContent)!=0)
864 ){
865 db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
866 }
867 @ <textarea name="%s(zFile)" rows="10" cols="80">\
868 @ %h(zContent)</textarea>
869 @ <br>
@@ -1042,10 +1048,11 @@
1048 @ <option value='%d(i)'>draft%d(i)</option>
1049 }
1050 }
1051 @ </select>
1052 @ </p>
1053 @ </form>
1054 @
1055 @ <a name='step2'></a>
1056 @ <h1>Step 2: Authenticate</h1>
1057 @
1058 if( isSetup ){
1059
+21 -1
--- src/style.c
+++ src/style.c
@@ -259,10 +259,11 @@
259259
}else{
260260
needHrefJs = 1;
261261
@ <form method="POST" data-action='%s(zLink)' action='%R/login' \
262262
@ %s(zOtherArgs)>
263263
}
264
+ login_insert_csrf_secret();
264265
}
265266
266267
/*
267268
** Add a new element to the submenu
268269
*/
@@ -1459,11 +1460,30 @@
14591460
@ g.zRepositoryName = %h(g.zRepositoryName)<br>
14601461
@ load_average() = %f(load_average())<br>
14611462
#ifndef _WIN32
14621463
@ RSS = %.2f(fossil_rss()/1000000.0) MB</br>
14631464
#endif
1464
- @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br>
1465
+ (void)cgi_csrf_safe(2);
1466
+ switch( g.okCsrf ){
1467
+ case 1: {
1468
+ @ CSRF safety = Same origin<br>
1469
+ break;
1470
+ }
1471
+ case 2: {
1472
+ @ CSRF safety = Same origin, POST<br>
1473
+ break;
1474
+ }
1475
+ case 3: {
1476
+ @ CSRF safety = Same origin, POST, CSRF token<br>
1477
+ break;
1478
+ }
1479
+ default: {
1480
+ @ CSRF safety = unsafe<br>
1481
+ break;
1482
+ }
1483
+ }
1484
+
14651485
@ fossil_exe_id() = %h(fossil_exe_id())<br>
14661486
if( g.perm.Admin ){
14671487
int k;
14681488
for(k=0; g.argvOrig[k]; k++){
14691489
Blob t;
14701490
--- src/style.c
+++ src/style.c
@@ -259,10 +259,11 @@
259 }else{
260 needHrefJs = 1;
261 @ <form method="POST" data-action='%s(zLink)' action='%R/login' \
262 @ %s(zOtherArgs)>
263 }
 
264 }
265
266 /*
267 ** Add a new element to the submenu
268 */
@@ -1459,11 +1460,30 @@
1459 @ g.zRepositoryName = %h(g.zRepositoryName)<br>
1460 @ load_average() = %f(load_average())<br>
1461 #ifndef _WIN32
1462 @ RSS = %.2f(fossil_rss()/1000000.0) MB</br>
1463 #endif
1464 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1465 @ fossil_exe_id() = %h(fossil_exe_id())<br>
1466 if( g.perm.Admin ){
1467 int k;
1468 for(k=0; g.argvOrig[k]; k++){
1469 Blob t;
1470
--- src/style.c
+++ src/style.c
@@ -259,10 +259,11 @@
259 }else{
260 needHrefJs = 1;
261 @ <form method="POST" data-action='%s(zLink)' action='%R/login' \
262 @ %s(zOtherArgs)>
263 }
264 login_insert_csrf_secret();
265 }
266
267 /*
268 ** Add a new element to the submenu
269 */
@@ -1459,11 +1460,30 @@
1460 @ g.zRepositoryName = %h(g.zRepositoryName)<br>
1461 @ load_average() = %f(load_average())<br>
1462 #ifndef _WIN32
1463 @ RSS = %.2f(fossil_rss()/1000000.0) MB</br>
1464 #endif
1465 (void)cgi_csrf_safe(2);
1466 switch( g.okCsrf ){
1467 case 1: {
1468 @ CSRF safety = Same origin<br>
1469 break;
1470 }
1471 case 2: {
1472 @ CSRF safety = Same origin, POST<br>
1473 break;
1474 }
1475 case 3: {
1476 @ CSRF safety = Same origin, POST, CSRF token<br>
1477 break;
1478 }
1479 default: {
1480 @ CSRF safety = unsafe<br>
1481 break;
1482 }
1483 }
1484
1485 @ fossil_exe_id() = %h(fossil_exe_id())<br>
1486 if( g.perm.Admin ){
1487 int k;
1488 for(k=0; g.argvOrig[k]; k++){
1489 Blob t;
1490
+3 -1
--- src/th_main.c
+++ src/th_main.c
@@ -605,11 +605,13 @@
605605
int *argl
606606
){
607607
if( argc!=1 ){
608608
return Th_WrongNumArgs(interp, "verifyCsrf");
609609
}
610
- login_verify_csrf_secret();
610
+ if( !cgi_csrf_safe(2) ){
611
+ fossil_fatal("possible CSRF attack");
612
+ }
611613
return TH_OK;
612614
}
613615
614616
/*
615617
** TH1 command: verifyLogin
616618
--- src/th_main.c
+++ src/th_main.c
@@ -605,11 +605,13 @@
605 int *argl
606 ){
607 if( argc!=1 ){
608 return Th_WrongNumArgs(interp, "verifyCsrf");
609 }
610 login_verify_csrf_secret();
 
 
611 return TH_OK;
612 }
613
614 /*
615 ** TH1 command: verifyLogin
616
--- src/th_main.c
+++ src/th_main.c
@@ -605,11 +605,13 @@
605 int *argl
606 ){
607 if( argc!=1 ){
608 return Th_WrongNumArgs(interp, "verifyCsrf");
609 }
610 if( !cgi_csrf_safe(2) ){
611 fossil_fatal("possible CSRF attack");
612 }
613 return TH_OK;
614 }
615
616 /*
617 ** TH1 command: verifyLogin
618
+4 -3
--- src/tkt.c
+++ src/tkt.c
@@ -900,11 +900,14 @@
900900
int i;
901901
int nJ = 0, rc = TH_OK;
902902
Blob tktchng, cksum;
903903
int needMod;
904904
905
- login_verify_csrf_secret();
905
+ if( !cgi_csrf_safe(2) ){
906
+ @ <p class="generalError">Error: Invalid CSRF token.</p>
907
+ return TH_OK;
908
+ }
906909
if( !captcha_is_correct(0) ){
907910
@ <p class="generalError">Error: Incorrect security code.</p>
908911
return TH_OK;
909912
}
910913
zUuid = (const char *)pUuid;
@@ -1015,11 +1018,10 @@
10151018
initializeVariablesFromCGI();
10161019
getAllTicketFields();
10171020
initializeVariablesFromDb();
10181021
if( g.zPath[0]=='d' ) showAllFields();
10191022
form_begin(0, "%R/%s", g.zPath);
1020
- login_insert_csrf_secret();
10211023
if( P("date_override") && g.perm.Setup ){
10221024
@ <input type="hidden" name="date_override" value="%h(P("date_override"))">
10231025
}
10241026
zScript = ticket_newpage_code();
10251027
if( g.zLogin && g.zLogin[0] ){
@@ -1105,11 +1107,10 @@
11051107
initializeVariablesFromCGI();
11061108
initializeVariablesFromDb();
11071109
if( g.zPath[0]=='d' ) showAllFields();
11081110
form_begin(0, "%R/%s", g.zPath);
11091111
@ <input type="hidden" name="name" value="%s(zName)">
1110
- login_insert_csrf_secret();
11111112
zScript = ticket_editpage_code();
11121113
Th_Store("login", login_name());
11131114
Th_Store("date", db_text(0, "SELECT datetime('now')"));
11141115
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
11151116
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
11161117
--- src/tkt.c
+++ src/tkt.c
@@ -900,11 +900,14 @@
900 int i;
901 int nJ = 0, rc = TH_OK;
902 Blob tktchng, cksum;
903 int needMod;
904
905 login_verify_csrf_secret();
 
 
 
906 if( !captcha_is_correct(0) ){
907 @ <p class="generalError">Error: Incorrect security code.</p>
908 return TH_OK;
909 }
910 zUuid = (const char *)pUuid;
@@ -1015,11 +1018,10 @@
1015 initializeVariablesFromCGI();
1016 getAllTicketFields();
1017 initializeVariablesFromDb();
1018 if( g.zPath[0]=='d' ) showAllFields();
1019 form_begin(0, "%R/%s", g.zPath);
1020 login_insert_csrf_secret();
1021 if( P("date_override") && g.perm.Setup ){
1022 @ <input type="hidden" name="date_override" value="%h(P("date_override"))">
1023 }
1024 zScript = ticket_newpage_code();
1025 if( g.zLogin && g.zLogin[0] ){
@@ -1105,11 +1107,10 @@
1105 initializeVariablesFromCGI();
1106 initializeVariablesFromDb();
1107 if( g.zPath[0]=='d' ) showAllFields();
1108 form_begin(0, "%R/%s", g.zPath);
1109 @ <input type="hidden" name="name" value="%s(zName)">
1110 login_insert_csrf_secret();
1111 zScript = ticket_editpage_code();
1112 Th_Store("login", login_name());
1113 Th_Store("date", db_text(0, "SELECT datetime('now')"));
1114 Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
1115 Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
1116
--- src/tkt.c
+++ src/tkt.c
@@ -900,11 +900,14 @@
900 int i;
901 int nJ = 0, rc = TH_OK;
902 Blob tktchng, cksum;
903 int needMod;
904
905 if( !cgi_csrf_safe(2) ){
906 @ <p class="generalError">Error: Invalid CSRF token.</p>
907 return TH_OK;
908 }
909 if( !captcha_is_correct(0) ){
910 @ <p class="generalError">Error: Incorrect security code.</p>
911 return TH_OK;
912 }
913 zUuid = (const char *)pUuid;
@@ -1015,11 +1018,10 @@
1018 initializeVariablesFromCGI();
1019 getAllTicketFields();
1020 initializeVariablesFromDb();
1021 if( g.zPath[0]=='d' ) showAllFields();
1022 form_begin(0, "%R/%s", g.zPath);
 
1023 if( P("date_override") && g.perm.Setup ){
1024 @ <input type="hidden" name="date_override" value="%h(P("date_override"))">
1025 }
1026 zScript = ticket_newpage_code();
1027 if( g.zLogin && g.zLogin[0] ){
@@ -1105,11 +1107,10 @@
1107 initializeVariablesFromCGI();
1108 initializeVariablesFromDb();
1109 if( g.zPath[0]=='d' ) showAllFields();
1110 form_begin(0, "%R/%s", g.zPath);
1111 @ <input type="hidden" name="name" value="%s(zName)">
 
1112 zScript = ticket_editpage_code();
1113 Th_Store("login", login_name());
1114 Th_Store("date", db_text(0, "SELECT datetime('now')"));
1115 Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
1116 Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
1117
+2 -4
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -135,18 +135,16 @@
135135
if( z==0 ){
136136
z = db_get(zDbField, zDfltValue);
137137
}
138138
style_set_current_feature("tktsetup");
139139
style_header("Edit %s", zTitle);
140
- if( P("clear")!=0 ){
141
- login_verify_csrf_secret();
140
+ if( P("clear")!=0 && cgi_csrf_safe(2) ){
142141
db_unset(zDbField/*works-like:"x"*/, 0);
143142
if( xRebuild ) xRebuild();
144143
cgi_redirect("tktsetup");
145
- }else if( isSubmit ){
144
+ }else if( isSubmit && cgi_csrf_safe(2) ){
146145
char *zErr = 0;
147
- login_verify_csrf_secret();
148146
if( xText && (zErr = xText(z))!=0 ){
149147
@ <p class="tktsetupError">ERROR: %h(zErr)</p>
150148
}else{
151149
db_set(zDbField/*works-like:"x"*/, z, 0);
152150
if( xRebuild ) xRebuild();
153151
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -135,18 +135,16 @@
135 if( z==0 ){
136 z = db_get(zDbField, zDfltValue);
137 }
138 style_set_current_feature("tktsetup");
139 style_header("Edit %s", zTitle);
140 if( P("clear")!=0 ){
141 login_verify_csrf_secret();
142 db_unset(zDbField/*works-like:"x"*/, 0);
143 if( xRebuild ) xRebuild();
144 cgi_redirect("tktsetup");
145 }else if( isSubmit ){
146 char *zErr = 0;
147 login_verify_csrf_secret();
148 if( xText && (zErr = xText(z))!=0 ){
149 @ <p class="tktsetupError">ERROR: %h(zErr)</p>
150 }else{
151 db_set(zDbField/*works-like:"x"*/, z, 0);
152 if( xRebuild ) xRebuild();
153
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -135,18 +135,16 @@
135 if( z==0 ){
136 z = db_get(zDbField, zDfltValue);
137 }
138 style_set_current_feature("tktsetup");
139 style_header("Edit %s", zTitle);
140 if( P("clear")!=0 && cgi_csrf_safe(2) ){
 
141 db_unset(zDbField/*works-like:"x"*/, 0);
142 if( xRebuild ) xRebuild();
143 cgi_redirect("tktsetup");
144 }else if( isSubmit && cgi_csrf_safe(2) ){
145 char *zErr = 0;
 
146 if( xText && (zErr = xText(z))!=0 ){
147 @ <p class="tktsetupError">ERROR: %h(zErr)</p>
148 }else{
149 db_set(zDbField/*works-like:"x"*/, z, 0);
150 if( xRebuild ) xRebuild();
151
+1 -2
--- src/wiki.c
+++ src/wiki.c
@@ -1632,18 +1632,18 @@
16321632
zMimetype = wiki_filter_mimetypes(pWiki->zMimetype)
16331633
/* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */;
16341634
}
16351635
if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0
16361636
&& (goodCaptcha = captcha_is_correct(0))
1637
+ && cgi_csrf_safe(2)
16371638
){
16381639
char *zDate;
16391640
Blob cksum;
16401641
Blob body;
16411642
Blob wiki;
16421643
16431644
blob_zero(&body);
1644
- login_verify_csrf_secret();
16451645
blob_append(&body, pWiki->zWiki, -1);
16461646
blob_zero(&wiki);
16471647
db_begin_transaction();
16481648
zDate = date_in_standard_format("now");
16491649
blob_appendf(&wiki, "D %s\n", zDate);
@@ -1695,11 +1695,10 @@
16951695
@ <hr>
16961696
blob_reset(&preview);
16971697
}
16981698
zUser = PD("u", g.zLogin);
16991699
form_begin(0, "%R/wikiappend");
1700
- login_insert_csrf_secret();
17011700
@ <input type="hidden" name="name" value="%h(zPageName)">
17021701
@ <input type="hidden" name="mimetype" value="%h(zMimetype)">
17031702
@ Your Name:
17041703
@ <input type="text" name="u" size="20" value="%h(zUser)"><br>
17051704
zFormat = mimetype_common_name(zMimetype);
17061705
--- src/wiki.c
+++ src/wiki.c
@@ -1632,18 +1632,18 @@
1632 zMimetype = wiki_filter_mimetypes(pWiki->zMimetype)
1633 /* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */;
1634 }
1635 if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0
1636 && (goodCaptcha = captcha_is_correct(0))
 
1637 ){
1638 char *zDate;
1639 Blob cksum;
1640 Blob body;
1641 Blob wiki;
1642
1643 blob_zero(&body);
1644 login_verify_csrf_secret();
1645 blob_append(&body, pWiki->zWiki, -1);
1646 blob_zero(&wiki);
1647 db_begin_transaction();
1648 zDate = date_in_standard_format("now");
1649 blob_appendf(&wiki, "D %s\n", zDate);
@@ -1695,11 +1695,10 @@
1695 @ <hr>
1696 blob_reset(&preview);
1697 }
1698 zUser = PD("u", g.zLogin);
1699 form_begin(0, "%R/wikiappend");
1700 login_insert_csrf_secret();
1701 @ <input type="hidden" name="name" value="%h(zPageName)">
1702 @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
1703 @ Your Name:
1704 @ <input type="text" name="u" size="20" value="%h(zUser)"><br>
1705 zFormat = mimetype_common_name(zMimetype);
1706
--- src/wiki.c
+++ src/wiki.c
@@ -1632,18 +1632,18 @@
1632 zMimetype = wiki_filter_mimetypes(pWiki->zMimetype)
1633 /* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */;
1634 }
1635 if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0
1636 && (goodCaptcha = captcha_is_correct(0))
1637 && cgi_csrf_safe(2)
1638 ){
1639 char *zDate;
1640 Blob cksum;
1641 Blob body;
1642 Blob wiki;
1643
1644 blob_zero(&body);
 
1645 blob_append(&body, pWiki->zWiki, -1);
1646 blob_zero(&wiki);
1647 db_begin_transaction();
1648 zDate = date_in_standard_format("now");
1649 blob_appendf(&wiki, "D %s\n", zDate);
@@ -1695,11 +1695,10 @@
1695 @ <hr>
1696 blob_reset(&preview);
1697 }
1698 zUser = PD("u", g.zLogin);
1699 form_begin(0, "%R/wikiappend");
 
1700 @ <input type="hidden" name="name" value="%h(zPageName)">
1701 @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
1702 @ Your Name:
1703 @ <input type="text" name="u" size="20" value="%h(zUser)"><br>
1704 zFormat = mimetype_common_name(zMimetype);
1705
+2 -4
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -118,18 +118,16 @@
118118
if( z==0 ){
119119
z = db_get(zDbField, zDfltValue);
120120
}
121121
style_set_current_feature("xfersetup");
122122
style_header("Edit %s", zTitle);
123
- if( P("clear")!=0 ){
124
- login_verify_csrf_secret();
123
+ if( P("clear")!=0 && cgi_csrf_safe(2) ){
125124
db_unset(zDbField/*works-like:"x"*/, 0);
126125
if( xRebuild ) xRebuild();
127126
z = zDfltValue;
128
- }else if( isSubmit ){
127
+ }else if( isSubmit && cgi_csrf_safe(2) ){
129128
char *zErr = 0;
130
- login_verify_csrf_secret();
131129
if( xText && (zErr = xText(z))!=0 ){
132130
@ <p class="xfersetupError">ERROR: %h(zErr)</p>
133131
}else{
134132
db_set(zDbField/*works-like:"x"*/, z, 0);
135133
if( xRebuild ) xRebuild();
136134
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -118,18 +118,16 @@
118 if( z==0 ){
119 z = db_get(zDbField, zDfltValue);
120 }
121 style_set_current_feature("xfersetup");
122 style_header("Edit %s", zTitle);
123 if( P("clear")!=0 ){
124 login_verify_csrf_secret();
125 db_unset(zDbField/*works-like:"x"*/, 0);
126 if( xRebuild ) xRebuild();
127 z = zDfltValue;
128 }else if( isSubmit ){
129 char *zErr = 0;
130 login_verify_csrf_secret();
131 if( xText && (zErr = xText(z))!=0 ){
132 @ <p class="xfersetupError">ERROR: %h(zErr)</p>
133 }else{
134 db_set(zDbField/*works-like:"x"*/, z, 0);
135 if( xRebuild ) xRebuild();
136
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -118,18 +118,16 @@
118 if( z==0 ){
119 z = db_get(zDbField, zDfltValue);
120 }
121 style_set_current_feature("xfersetup");
122 style_header("Edit %s", zTitle);
123 if( P("clear")!=0 && cgi_csrf_safe(2) ){
 
124 db_unset(zDbField/*works-like:"x"*/, 0);
125 if( xRebuild ) xRebuild();
126 z = zDfltValue;
127 }else if( isSubmit && cgi_csrf_safe(2) ){
128 char *zErr = 0;
 
129 if( xText && (zErr = xText(z))!=0 ){
130 @ <p class="xfersetupError">ERROR: %h(zErr)</p>
131 }else{
132 db_set(zDbField/*works-like:"x"*/, z, 0);
133 if( xRebuild ) xRebuild();
134

Keyboard Shortcuts

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