Fossil SCM

Enhancement to codecheck1.c to verify that routines like db_set() use a string literal as the setting argument, and are thus impervious to injection attacks.

drh 2021-07-08 17:43 trunk
Commit 0a5d0e191cd6ff1dae343b85accf0da1aaf1d2e4be426ebed3863a361bf08623
+1 -1
--- src/alerts.c
+++ src/alerts.c
@@ -1153,11 +1153,11 @@
11531153
const char *zLabel = g.argv[3];
11541154
if( strncmp(zLabel, "email-", 6)!=0
11551155
|| (pSetting = db_find_setting(zLabel, 1))==0 ){
11561156
fossil_fatal("not a valid email setting: \"%s\"", zLabel);
11571157
}
1158
- db_set(pSetting->name, g.argv[4], isGlobal);
1158
+ db_set(pSetting->name/*works-like:""*/, g.argv[4], isGlobal);
11591159
g.argc = 3;
11601160
}
11611161
pSetting = setting_info(&nSetting);
11621162
for(; nSetting>0; nSetting--, pSetting++ ){
11631163
if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
11641164
--- src/alerts.c
+++ src/alerts.c
@@ -1153,11 +1153,11 @@
1153 const char *zLabel = g.argv[3];
1154 if( strncmp(zLabel, "email-", 6)!=0
1155 || (pSetting = db_find_setting(zLabel, 1))==0 ){
1156 fossil_fatal("not a valid email setting: \"%s\"", zLabel);
1157 }
1158 db_set(pSetting->name, g.argv[4], isGlobal);
1159 g.argc = 3;
1160 }
1161 pSetting = setting_info(&nSetting);
1162 for(; nSetting>0; nSetting--, pSetting++ ){
1163 if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
1164
--- src/alerts.c
+++ src/alerts.c
@@ -1153,11 +1153,11 @@
1153 const char *zLabel = g.argv[3];
1154 if( strncmp(zLabel, "email-", 6)!=0
1155 || (pSetting = db_find_setting(zLabel, 1))==0 ){
1156 fossil_fatal("not a valid email setting: \"%s\"", zLabel);
1157 }
1158 db_set(pSetting->name/*works-like:""*/, g.argv[4], isGlobal);
1159 g.argc = 3;
1160 }
1161 pSetting = setting_info(&nSetting);
1162 for(; nSetting>0; nSetting--, pSetting++ ){
1163 if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
1164
+1 -1
--- src/bisect.c
+++ src/bisect.c
@@ -673,11 +673,11 @@
673673
n = strlen(g.argv[3]);
674674
for(i=0; i<count(aBisectOption); i++){
675675
if( strncmp(g.argv[3], aBisectOption[i].zName, n)==0 ){
676676
char *z = mprintf("bisect-%s", aBisectOption[i].zName);
677677
if( g.argc==5 ){
678
- db_lset(z, g.argv[4]);
678
+ db_lset(z/*works-like:"bisect-%s"*/, g.argv[4]);
679679
}
680680
fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault));
681681
fossil_free(z);
682682
break;
683683
}
684684
--- src/bisect.c
+++ src/bisect.c
@@ -673,11 +673,11 @@
673 n = strlen(g.argv[3]);
674 for(i=0; i<count(aBisectOption); i++){
675 if( strncmp(g.argv[3], aBisectOption[i].zName, n)==0 ){
676 char *z = mprintf("bisect-%s", aBisectOption[i].zName);
677 if( g.argc==5 ){
678 db_lset(z, g.argv[4]);
679 }
680 fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault));
681 fossil_free(z);
682 break;
683 }
684
--- src/bisect.c
+++ src/bisect.c
@@ -673,11 +673,11 @@
673 n = strlen(g.argv[3]);
674 for(i=0; i<count(aBisectOption); i++){
675 if( strncmp(g.argv[3], aBisectOption[i].zName, n)==0 ){
676 char *z = mprintf("bisect-%s", aBisectOption[i].zName);
677 if( g.argc==5 ){
678 db_lset(z/*works-like:"bisect-%s"*/, g.argv[4]);
679 }
680 fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault));
681 fossil_free(z);
682 break;
683 }
684
+1 -3
--- src/checkout.c
+++ src/checkout.c
@@ -418,13 +418,11 @@
418418
&& db_exists("SELECT 1 FROM localdb.stash")
419419
){
420420
fossil_fatal("closing the checkout will delete your stash");
421421
}
422422
if( db_is_writeable("repository") ){
423
- char *zUnset = mprintf("ckout:%q", g.zLocalRoot);
424
- db_unset(zUnset, 1);
425
- fossil_free(zUnset);
423
+ db_unset_mprintf(1, "ckout:%q", g.zLocalRoot);
426424
}
427425
unlink_local_database(1);
428426
db_close(1);
429427
unlink_local_database(0);
430428
}
431429
--- src/checkout.c
+++ src/checkout.c
@@ -418,13 +418,11 @@
418 && db_exists("SELECT 1 FROM localdb.stash")
419 ){
420 fossil_fatal("closing the checkout will delete your stash");
421 }
422 if( db_is_writeable("repository") ){
423 char *zUnset = mprintf("ckout:%q", g.zLocalRoot);
424 db_unset(zUnset, 1);
425 fossil_free(zUnset);
426 }
427 unlink_local_database(1);
428 db_close(1);
429 unlink_local_database(0);
430 }
431
--- src/checkout.c
+++ src/checkout.c
@@ -418,13 +418,11 @@
418 && db_exists("SELECT 1 FROM localdb.stash")
419 ){
420 fossil_fatal("closing the checkout will delete your stash");
421 }
422 if( db_is_writeable("repository") ){
423 db_unset_mprintf(1, "ckout:%q", g.zLocalRoot);
 
 
424 }
425 unlink_local_database(1);
426 db_close(1);
427 unlink_local_database(0);
428 }
429
+2 -6
--- src/clone.c
+++ src/clone.c
@@ -314,26 +314,24 @@
314314
void remember_or_get_http_auth(
315315
const char *zHttpAuth, /* Credentials in the form "user:password" */
316316
int fRemember, /* True to remember credentials for later reuse */
317317
const char *zUrl /* URL for which these credentials apply */
318318
){
319
- char *zKey = mprintf("http-auth:%s", g.url.canonical);
320319
if( zHttpAuth && zHttpAuth[0] ){
321320
g.zHttpAuth = mprintf("%s", zHttpAuth);
322321
}
323322
if( fRemember ){
324323
if( g.zHttpAuth && g.zHttpAuth[0] ){
325324
set_httpauth(g.zHttpAuth);
326325
}else if( zUrl && zUrl[0] ){
327
- db_unset(zKey, 0);
326
+ db_unset_mprintf(0, "http-auth:%s", g.url.canonical);
328327
}else{
329328
g.zHttpAuth = get_httpauth();
330329
}
331330
}else if( g.zHttpAuth==0 && zUrl==0 ){
332331
g.zHttpAuth = get_httpauth();
333332
}
334
- free(zKey);
335333
}
336334
337335
/*
338336
** Get the HTTP Authorization preference from db.
339337
*/
@@ -346,13 +344,11 @@
346344
347345
/*
348346
** Set the HTTP Authorization preference in db.
349347
*/
350348
void set_httpauth(const char *zHttpAuth){
351
- char *zKey = mprintf("http-auth:%s", g.url.canonical);
352
- db_set(zKey, obscure(zHttpAuth), 0);
353
- free(zKey);
349
+ db_set_mprintf(obscure(zHttpAuth), 0, "http-auth:%s", g.url.canonical);
354350
}
355351
356352
/*
357353
** Look for SSH clone command line options and setup in globals.
358354
*/
359355
--- src/clone.c
+++ src/clone.c
@@ -314,26 +314,24 @@
314 void remember_or_get_http_auth(
315 const char *zHttpAuth, /* Credentials in the form "user:password" */
316 int fRemember, /* True to remember credentials for later reuse */
317 const char *zUrl /* URL for which these credentials apply */
318 ){
319 char *zKey = mprintf("http-auth:%s", g.url.canonical);
320 if( zHttpAuth && zHttpAuth[0] ){
321 g.zHttpAuth = mprintf("%s", zHttpAuth);
322 }
323 if( fRemember ){
324 if( g.zHttpAuth && g.zHttpAuth[0] ){
325 set_httpauth(g.zHttpAuth);
326 }else if( zUrl && zUrl[0] ){
327 db_unset(zKey, 0);
328 }else{
329 g.zHttpAuth = get_httpauth();
330 }
331 }else if( g.zHttpAuth==0 && zUrl==0 ){
332 g.zHttpAuth = get_httpauth();
333 }
334 free(zKey);
335 }
336
337 /*
338 ** Get the HTTP Authorization preference from db.
339 */
@@ -346,13 +344,11 @@
346
347 /*
348 ** Set the HTTP Authorization preference in db.
349 */
350 void set_httpauth(const char *zHttpAuth){
351 char *zKey = mprintf("http-auth:%s", g.url.canonical);
352 db_set(zKey, obscure(zHttpAuth), 0);
353 free(zKey);
354 }
355
356 /*
357 ** Look for SSH clone command line options and setup in globals.
358 */
359
--- src/clone.c
+++ src/clone.c
@@ -314,26 +314,24 @@
314 void remember_or_get_http_auth(
315 const char *zHttpAuth, /* Credentials in the form "user:password" */
316 int fRemember, /* True to remember credentials for later reuse */
317 const char *zUrl /* URL for which these credentials apply */
318 ){
 
319 if( zHttpAuth && zHttpAuth[0] ){
320 g.zHttpAuth = mprintf("%s", zHttpAuth);
321 }
322 if( fRemember ){
323 if( g.zHttpAuth && g.zHttpAuth[0] ){
324 set_httpauth(g.zHttpAuth);
325 }else if( zUrl && zUrl[0] ){
326 db_unset_mprintf(0, "http-auth:%s", g.url.canonical);
327 }else{
328 g.zHttpAuth = get_httpauth();
329 }
330 }else if( g.zHttpAuth==0 && zUrl==0 ){
331 g.zHttpAuth = get_httpauth();
332 }
 
333 }
334
335 /*
336 ** Get the HTTP Authorization preference from db.
337 */
@@ -346,13 +344,11 @@
344
345 /*
346 ** Set the HTTP Authorization preference in db.
347 */
348 void set_httpauth(const char *zHttpAuth){
349 db_set_mprintf(obscure(zHttpAuth), 0, "http-auth:%s", g.url.canonical);
 
 
350 }
351
352 /*
353 ** Look for SSH clone command line options and setup in globals.
354 */
355
+91 -58
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -347,10 +347,12 @@
347347
*/
348348
#define FMT_SQL 0x00001 /* Generator for SQL text */
349349
#define FMT_HTML 0x00002 /* Generator for HTML text */
350350
#define FMT_URL 0x00004 /* Generator for URLs */
351351
#define FMT_SAFE 0x00008 /* Generator for human-readable text */
352
+#define FMT_LIT 0x00010 /* Just verify that a string literal */
353
+#define FMT_PX 0x00020 /* Must have a literal prefix in format string */
352354
353355
/*
354356
** A list of internal Fossil interfaces that take a printf-style format
355357
** string.
356358
*/
@@ -357,65 +359,76 @@
357359
struct FmtFunc {
358360
const char *zFName; /* Name of the function */
359361
int iFmtArg; /* Index of format argument. Leftmost is 1. */
360362
unsigned fmtFlags; /* Processing flags */
361363
} aFmtFunc[] = {
362
- { "admin_log", 1, FMT_SAFE },
363
- { "audit_append", 3, FMT_SAFE },
364
- { "backofficeTrace", 1, FMT_SAFE },
365
- { "blob_append_sql", 2, FMT_SQL },
366
- { "blob_appendf", 2, FMT_SAFE },
367
- { "cgi_debug", 1, FMT_SAFE },
368
- { "cgi_panic", 1, FMT_SAFE },
369
- { "cgi_printf", 1, FMT_HTML },
370
- { "cgi_printf_header", 1, FMT_HTML },
371
- { "cgi_redirectf", 1, FMT_URL },
372
- { "chref", 2, FMT_URL },
373
- { "CX", 1, FMT_HTML },
374
- { "db_blob", 2, FMT_SQL },
375
- { "db_debug", 1, FMT_SQL },
376
- { "db_double", 2, FMT_SQL },
377
- { "db_err", 1, FMT_SAFE },
378
- { "db_exists", 1, FMT_SQL },
379
- { "db_get_mprintf", 2, FMT_SAFE },
380
- { "db_int", 2, FMT_SQL },
381
- { "db_int64", 2, FMT_SQL },
382
- { "db_multi_exec", 1, FMT_SQL },
383
- { "db_optional_sql", 2, FMT_SQL },
384
- { "db_prepare", 2, FMT_SQL },
385
- { "db_prepare_ignore_error", 2, FMT_SQL },
386
- { "db_set_mprintf", 3, FMT_SAFE },
387
- { "db_static_prepare", 2, FMT_SQL },
388
- { "db_text", 2, FMT_SQL },
389
- { "db_unset_mprintf", 2, FMT_SAFE },
390
- { "emailerError", 2, FMT_SAFE },
391
- { "fileedit_ajax_error", 2, FMT_SAFE },
392
- { "form_begin", 2, FMT_URL },
393
- { "fossil_error", 2, FMT_SAFE },
394
- { "fossil_errorlog", 1, FMT_SAFE },
395
- { "fossil_fatal", 1, FMT_SAFE },
396
- { "fossil_fatal_recursive", 1, FMT_SAFE },
397
- { "fossil_panic", 1, FMT_SAFE },
398
- { "fossil_print", 1, FMT_SAFE },
399
- { "fossil_trace", 1, FMT_SAFE },
400
- { "fossil_warning", 1, FMT_SAFE },
401
- { "href", 1, FMT_URL },
402
- { "json_new_string_f", 1, FMT_SAFE },
403
- { "json_set_err", 2, FMT_SAFE },
404
- { "json_warn", 2, FMT_SAFE },
405
- { "mprintf", 1, FMT_SAFE },
406
- { "pop3_print", 2, FMT_SAFE },
407
- { "smtp_send_line", 2, FMT_SAFE },
408
- { "smtp_server_send", 2, FMT_SAFE },
409
- { "socket_set_errmsg", 1, FMT_SAFE },
410
- { "ssl_set_errmsg", 1, FMT_SAFE },
411
- { "style_header", 1, FMT_HTML },
412
- { "style_set_current_page", 1, FMT_URL },
413
- { "style_submenu_element", 2, FMT_URL },
414
- { "style_submenu_sql", 3, FMT_SQL },
415
- { "webpage_error", 1, FMT_SAFE },
416
- { "xhref", 2, FMT_URL },
364
+ { "admin_log", 1, FMT_SAFE },
365
+ { "audit_append", 3, FMT_SAFE },
366
+ { "backofficeTrace", 1, FMT_SAFE },
367
+ { "blob_append_sql", 2, FMT_SQL },
368
+ { "blob_appendf", 2, FMT_SAFE },
369
+ { "cgi_debug", 1, FMT_SAFE },
370
+ { "cgi_panic", 1, FMT_SAFE },
371
+ { "cgi_printf", 1, FMT_HTML },
372
+ { "cgi_printf_header", 1, FMT_HTML },
373
+ { "cgi_redirectf", 1, FMT_URL },
374
+ { "chref", 2, FMT_URL },
375
+ { "CX", 1, FMT_HTML },
376
+ { "db_blob", 2, FMT_SQL },
377
+ { "db_debug", 1, FMT_SQL },
378
+ { "db_double", 2, FMT_SQL },
379
+ { "db_err", 1, FMT_SAFE },
380
+ { "db_exists", 1, FMT_SQL },
381
+ { "db_get_mprintf", 2, FMT_SAFE },
382
+ { "db_int", 2, FMT_SQL },
383
+ { "db_int64", 2, FMT_SQL },
384
+ { "db_lset", 1, FMT_LIT },
385
+ { "db_lset_int", 1, FMT_LIT },
386
+ { "db_multi_exec", 1, FMT_SQL },
387
+ { "db_optional_sql", 2, FMT_SQL },
388
+ { "db_prepare", 2, FMT_SQL },
389
+ { "db_prepare_ignore_error", 2, FMT_SQL },
390
+ { "db_set", 1, FMT_LIT },
391
+ { "db_set_int", 1, FMT_LIT },
392
+ { "db_set_mprintf", 3, FMT_PX },
393
+ { "db_static_prepare", 2, FMT_SQL },
394
+ { "db_text", 2, FMT_SQL },
395
+ { "db_unset", 1, FMT_LIT },
396
+ { "db_unset_mprintf", 2, FMT_PX },
397
+ { "emailerError", 2, FMT_SAFE },
398
+ { "entry_attribute", 4, FMT_LIT },
399
+ { "fileedit_ajax_error", 2, FMT_SAFE },
400
+ { "form_begin", 2, FMT_URL },
401
+ { "fossil_error", 2, FMT_SAFE },
402
+ { "fossil_errorlog", 1, FMT_SAFE },
403
+ { "fossil_fatal", 1, FMT_SAFE },
404
+ { "fossil_fatal_recursive", 1, FMT_SAFE },
405
+ { "fossil_panic", 1, FMT_SAFE },
406
+ { "fossil_print", 1, FMT_SAFE },
407
+ { "fossil_trace", 1, FMT_SAFE },
408
+ { "fossil_warning", 1, FMT_SAFE },
409
+ { "href", 1, FMT_URL },
410
+ { "json_new_string_f", 1, FMT_SAFE },
411
+ { "json_set_err", 2, FMT_SAFE },
412
+ { "json_warn", 2, FMT_SAFE },
413
+ { "mprintf", 1, FMT_SAFE },
414
+ { "multiple_choice_attribute", 3, FMT_LIT },
415
+ { "onoff_attribute", 3, FMT_LIT },
416
+ { "pop3_print", 2, FMT_SAFE },
417
+ { "smtp_send_line", 2, FMT_SAFE },
418
+ { "smtp_server_send", 2, FMT_SAFE },
419
+ { "socket_set_errmsg", 1, FMT_SAFE },
420
+ { "ssl_set_errmsg", 1, FMT_SAFE },
421
+ { "style_header", 1, FMT_HTML },
422
+ { "style_set_current_page", 1, FMT_URL },
423
+ { "style_submenu_element", 2, FMT_URL },
424
+ { "style_submenu_sql", 3, FMT_SQL },
425
+ { "textarea_attribute", 5, FMT_LIT },
426
+ { "tktsetup_generic", 1, FMT_LIT },
427
+ { "webpage_error", 1, FMT_SAFE },
428
+ { "xfersetup_generic", 1, FMT_LIT },
429
+ { "xhref", 2, FMT_URL },
417430
};
418431
419432
/*
420433
** Comparison function for two FmtFunc entries
421434
*/
@@ -459,20 +472,26 @@
459472
** Return the expected number of arguments for the format string.
460473
** Return -1 if the value cannot be computed.
461474
**
462475
** For each argument less than nType, store the conversion character
463476
** for that argument in cType[i].
477
+**
478
+** Store the number of initial literal characters of the format string
479
+** in *pInit.
464480
*/
465
-static int formatArgCount(const char *z, int nType, char *cType){
481
+static int formatArgCount(const char *z, int nType, char *cType, int *pInit){
466482
int nArg = 0;
467483
int i, k;
468484
int len;
469485
int eType;
470486
int ln = 0;
487
+ *pInit = 0;
471488
while( z[0] ){
472489
len = token_length(z, &eType, &ln);
473490
if( eType==TK_STR ){
491
+ for(i=1; i<len-1 && isalpha(z[i]); i++){}
492
+ *pInit = i-1;
474493
for(i=1; i<len-1; i++){
475494
if( z[i]!='%' ) continue;
476495
if( z[i+1]=='%' ){ i++; continue; }
477496
for(k=i+1; k<len && !isalpha(z[k]); k++){
478497
if( z[k]=='*' || z[k]=='#' ){
@@ -515,10 +534,11 @@
515534
int nArg = 0;
516535
const char **azArg = 0;
517536
int i, k;
518537
int nErr = 0;
519538
char *acType;
539
+ int nInit = 0;
520540
521541
szFName = token_length(zFCall, &eToken, &ln);
522542
zStart = next_non_whitespace(zFCall+szFName, &len, &eToken);
523543
assert( zStart[0]=='(' && len==1 );
524544
len = distance_to(zStart+1, ')');
@@ -545,21 +565,34 @@
545565
nErr++;
546566
}else{
547567
const char *zFmt = azArg[fmtArg-1];
548568
const char *zOverride = strstr(zFmt, "/*works-like:");
549569
if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1;
550
- if( !is_string_lit(zFmt) ){
570
+ if( fmtFlags & FMT_LIT ){
571
+ if( !is_string_lit(zFmt) ){
572
+ printf("%s:%d: argument %d to %.*s() should be a string literal\n",
573
+ zFilename, lnFCall, fmtArg, szFName, zFCall);
574
+ nErr++;
575
+ }
576
+ }else if( !is_string_lit(zFmt) ){
551577
printf("%s:%d: %.*s() has non-constant format on arg[%d]\n",
552578
zFilename, lnFCall, szFName, zFCall, fmtArg-1);
553579
nErr++;
554
- }else if( (k = formatArgCount(zFmt, nArg, acType))>=0
580
+ }else if( (k = formatArgCount(zFmt, nArg, acType, &nInit))>=0
555581
&& nArg!=fmtArg+k ){
556582
printf("%s:%d: too %s arguments to %.*s() "
557583
"- got %d and expected %d\n",
558584
zFilename, lnFCall, (nArg<fmtArg+k ? "few" : "many"),
559585
szFName, zFCall, nArg, fmtArg+k);
560586
nErr++;
587
+ }else if( (fmtFlags & FMT_PX)!=0 ){
588
+ if( nInit==0 ){
589
+ printf("%s:%d: format string on %.*s() should have"
590
+ " an ASCII character prefix\n",
591
+ zFilename, lnFCall, szFName, zFCall);
592
+ nErr++;
593
+ }
561594
}else if( (fmtFlags & FMT_SAFE)==0 ){
562595
for(i=0; i<nArg && i<k; i++){
563596
if( (acType[i]=='s' || acType[i]=='z' || acType[i]=='b') ){
564597
const char *zExpr = azArg[fmtArg+i];
565598
if( never_safe(zExpr) ){
566599
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -347,10 +347,12 @@
347 */
348 #define FMT_SQL 0x00001 /* Generator for SQL text */
349 #define FMT_HTML 0x00002 /* Generator for HTML text */
350 #define FMT_URL 0x00004 /* Generator for URLs */
351 #define FMT_SAFE 0x00008 /* Generator for human-readable text */
 
 
352
353 /*
354 ** A list of internal Fossil interfaces that take a printf-style format
355 ** string.
356 */
@@ -357,65 +359,76 @@
357 struct FmtFunc {
358 const char *zFName; /* Name of the function */
359 int iFmtArg; /* Index of format argument. Leftmost is 1. */
360 unsigned fmtFlags; /* Processing flags */
361 } aFmtFunc[] = {
362 { "admin_log", 1, FMT_SAFE },
363 { "audit_append", 3, FMT_SAFE },
364 { "backofficeTrace", 1, FMT_SAFE },
365 { "blob_append_sql", 2, FMT_SQL },
366 { "blob_appendf", 2, FMT_SAFE },
367 { "cgi_debug", 1, FMT_SAFE },
368 { "cgi_panic", 1, FMT_SAFE },
369 { "cgi_printf", 1, FMT_HTML },
370 { "cgi_printf_header", 1, FMT_HTML },
371 { "cgi_redirectf", 1, FMT_URL },
372 { "chref", 2, FMT_URL },
373 { "CX", 1, FMT_HTML },
374 { "db_blob", 2, FMT_SQL },
375 { "db_debug", 1, FMT_SQL },
376 { "db_double", 2, FMT_SQL },
377 { "db_err", 1, FMT_SAFE },
378 { "db_exists", 1, FMT_SQL },
379 { "db_get_mprintf", 2, FMT_SAFE },
380 { "db_int", 2, FMT_SQL },
381 { "db_int64", 2, FMT_SQL },
382 { "db_multi_exec", 1, FMT_SQL },
383 { "db_optional_sql", 2, FMT_SQL },
384 { "db_prepare", 2, FMT_SQL },
385 { "db_prepare_ignore_error", 2, FMT_SQL },
386 { "db_set_mprintf", 3, FMT_SAFE },
387 { "db_static_prepare", 2, FMT_SQL },
388 { "db_text", 2, FMT_SQL },
389 { "db_unset_mprintf", 2, FMT_SAFE },
390 { "emailerError", 2, FMT_SAFE },
391 { "fileedit_ajax_error", 2, FMT_SAFE },
392 { "form_begin", 2, FMT_URL },
393 { "fossil_error", 2, FMT_SAFE },
394 { "fossil_errorlog", 1, FMT_SAFE },
395 { "fossil_fatal", 1, FMT_SAFE },
396 { "fossil_fatal_recursive", 1, FMT_SAFE },
397 { "fossil_panic", 1, FMT_SAFE },
398 { "fossil_print", 1, FMT_SAFE },
399 { "fossil_trace", 1, FMT_SAFE },
400 { "fossil_warning", 1, FMT_SAFE },
401 { "href", 1, FMT_URL },
402 { "json_new_string_f", 1, FMT_SAFE },
403 { "json_set_err", 2, FMT_SAFE },
404 { "json_warn", 2, FMT_SAFE },
405 { "mprintf", 1, FMT_SAFE },
406 { "pop3_print", 2, FMT_SAFE },
407 { "smtp_send_line", 2, FMT_SAFE },
408 { "smtp_server_send", 2, FMT_SAFE },
409 { "socket_set_errmsg", 1, FMT_SAFE },
410 { "ssl_set_errmsg", 1, FMT_SAFE },
411 { "style_header", 1, FMT_HTML },
412 { "style_set_current_page", 1, FMT_URL },
413 { "style_submenu_element", 2, FMT_URL },
414 { "style_submenu_sql", 3, FMT_SQL },
415 { "webpage_error", 1, FMT_SAFE },
416 { "xhref", 2, FMT_URL },
 
 
 
 
 
 
 
 
 
 
 
417 };
418
419 /*
420 ** Comparison function for two FmtFunc entries
421 */
@@ -459,20 +472,26 @@
459 ** Return the expected number of arguments for the format string.
460 ** Return -1 if the value cannot be computed.
461 **
462 ** For each argument less than nType, store the conversion character
463 ** for that argument in cType[i].
 
 
 
464 */
465 static int formatArgCount(const char *z, int nType, char *cType){
466 int nArg = 0;
467 int i, k;
468 int len;
469 int eType;
470 int ln = 0;
 
471 while( z[0] ){
472 len = token_length(z, &eType, &ln);
473 if( eType==TK_STR ){
 
 
474 for(i=1; i<len-1; i++){
475 if( z[i]!='%' ) continue;
476 if( z[i+1]=='%' ){ i++; continue; }
477 for(k=i+1; k<len && !isalpha(z[k]); k++){
478 if( z[k]=='*' || z[k]=='#' ){
@@ -515,10 +534,11 @@
515 int nArg = 0;
516 const char **azArg = 0;
517 int i, k;
518 int nErr = 0;
519 char *acType;
 
520
521 szFName = token_length(zFCall, &eToken, &ln);
522 zStart = next_non_whitespace(zFCall+szFName, &len, &eToken);
523 assert( zStart[0]=='(' && len==1 );
524 len = distance_to(zStart+1, ')');
@@ -545,21 +565,34 @@
545 nErr++;
546 }else{
547 const char *zFmt = azArg[fmtArg-1];
548 const char *zOverride = strstr(zFmt, "/*works-like:");
549 if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1;
550 if( !is_string_lit(zFmt) ){
 
 
 
 
 
 
551 printf("%s:%d: %.*s() has non-constant format on arg[%d]\n",
552 zFilename, lnFCall, szFName, zFCall, fmtArg-1);
553 nErr++;
554 }else if( (k = formatArgCount(zFmt, nArg, acType))>=0
555 && nArg!=fmtArg+k ){
556 printf("%s:%d: too %s arguments to %.*s() "
557 "- got %d and expected %d\n",
558 zFilename, lnFCall, (nArg<fmtArg+k ? "few" : "many"),
559 szFName, zFCall, nArg, fmtArg+k);
560 nErr++;
 
 
 
 
 
 
 
561 }else if( (fmtFlags & FMT_SAFE)==0 ){
562 for(i=0; i<nArg && i<k; i++){
563 if( (acType[i]=='s' || acType[i]=='z' || acType[i]=='b') ){
564 const char *zExpr = azArg[fmtArg+i];
565 if( never_safe(zExpr) ){
566
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -347,10 +347,12 @@
347 */
348 #define FMT_SQL 0x00001 /* Generator for SQL text */
349 #define FMT_HTML 0x00002 /* Generator for HTML text */
350 #define FMT_URL 0x00004 /* Generator for URLs */
351 #define FMT_SAFE 0x00008 /* Generator for human-readable text */
352 #define FMT_LIT 0x00010 /* Just verify that a string literal */
353 #define FMT_PX 0x00020 /* Must have a literal prefix in format string */
354
355 /*
356 ** A list of internal Fossil interfaces that take a printf-style format
357 ** string.
358 */
@@ -357,65 +359,76 @@
359 struct FmtFunc {
360 const char *zFName; /* Name of the function */
361 int iFmtArg; /* Index of format argument. Leftmost is 1. */
362 unsigned fmtFlags; /* Processing flags */
363 } aFmtFunc[] = {
364 { "admin_log", 1, FMT_SAFE },
365 { "audit_append", 3, FMT_SAFE },
366 { "backofficeTrace", 1, FMT_SAFE },
367 { "blob_append_sql", 2, FMT_SQL },
368 { "blob_appendf", 2, FMT_SAFE },
369 { "cgi_debug", 1, FMT_SAFE },
370 { "cgi_panic", 1, FMT_SAFE },
371 { "cgi_printf", 1, FMT_HTML },
372 { "cgi_printf_header", 1, FMT_HTML },
373 { "cgi_redirectf", 1, FMT_URL },
374 { "chref", 2, FMT_URL },
375 { "CX", 1, FMT_HTML },
376 { "db_blob", 2, FMT_SQL },
377 { "db_debug", 1, FMT_SQL },
378 { "db_double", 2, FMT_SQL },
379 { "db_err", 1, FMT_SAFE },
380 { "db_exists", 1, FMT_SQL },
381 { "db_get_mprintf", 2, FMT_SAFE },
382 { "db_int", 2, FMT_SQL },
383 { "db_int64", 2, FMT_SQL },
384 { "db_lset", 1, FMT_LIT },
385 { "db_lset_int", 1, FMT_LIT },
386 { "db_multi_exec", 1, FMT_SQL },
387 { "db_optional_sql", 2, FMT_SQL },
388 { "db_prepare", 2, FMT_SQL },
389 { "db_prepare_ignore_error", 2, FMT_SQL },
390 { "db_set", 1, FMT_LIT },
391 { "db_set_int", 1, FMT_LIT },
392 { "db_set_mprintf", 3, FMT_PX },
393 { "db_static_prepare", 2, FMT_SQL },
394 { "db_text", 2, FMT_SQL },
395 { "db_unset", 1, FMT_LIT },
396 { "db_unset_mprintf", 2, FMT_PX },
397 { "emailerError", 2, FMT_SAFE },
398 { "entry_attribute", 4, FMT_LIT },
399 { "fileedit_ajax_error", 2, FMT_SAFE },
400 { "form_begin", 2, FMT_URL },
401 { "fossil_error", 2, FMT_SAFE },
402 { "fossil_errorlog", 1, FMT_SAFE },
403 { "fossil_fatal", 1, FMT_SAFE },
404 { "fossil_fatal_recursive", 1, FMT_SAFE },
405 { "fossil_panic", 1, FMT_SAFE },
406 { "fossil_print", 1, FMT_SAFE },
407 { "fossil_trace", 1, FMT_SAFE },
408 { "fossil_warning", 1, FMT_SAFE },
409 { "href", 1, FMT_URL },
410 { "json_new_string_f", 1, FMT_SAFE },
411 { "json_set_err", 2, FMT_SAFE },
412 { "json_warn", 2, FMT_SAFE },
413 { "mprintf", 1, FMT_SAFE },
414 { "multiple_choice_attribute", 3, FMT_LIT },
415 { "onoff_attribute", 3, FMT_LIT },
416 { "pop3_print", 2, FMT_SAFE },
417 { "smtp_send_line", 2, FMT_SAFE },
418 { "smtp_server_send", 2, FMT_SAFE },
419 { "socket_set_errmsg", 1, FMT_SAFE },
420 { "ssl_set_errmsg", 1, FMT_SAFE },
421 { "style_header", 1, FMT_HTML },
422 { "style_set_current_page", 1, FMT_URL },
423 { "style_submenu_element", 2, FMT_URL },
424 { "style_submenu_sql", 3, FMT_SQL },
425 { "textarea_attribute", 5, FMT_LIT },
426 { "tktsetup_generic", 1, FMT_LIT },
427 { "webpage_error", 1, FMT_SAFE },
428 { "xfersetup_generic", 1, FMT_LIT },
429 { "xhref", 2, FMT_URL },
430 };
431
432 /*
433 ** Comparison function for two FmtFunc entries
434 */
@@ -459,20 +472,26 @@
472 ** Return the expected number of arguments for the format string.
473 ** Return -1 if the value cannot be computed.
474 **
475 ** For each argument less than nType, store the conversion character
476 ** for that argument in cType[i].
477 **
478 ** Store the number of initial literal characters of the format string
479 ** in *pInit.
480 */
481 static int formatArgCount(const char *z, int nType, char *cType, int *pInit){
482 int nArg = 0;
483 int i, k;
484 int len;
485 int eType;
486 int ln = 0;
487 *pInit = 0;
488 while( z[0] ){
489 len = token_length(z, &eType, &ln);
490 if( eType==TK_STR ){
491 for(i=1; i<len-1 && isalpha(z[i]); i++){}
492 *pInit = i-1;
493 for(i=1; i<len-1; i++){
494 if( z[i]!='%' ) continue;
495 if( z[i+1]=='%' ){ i++; continue; }
496 for(k=i+1; k<len && !isalpha(z[k]); k++){
497 if( z[k]=='*' || z[k]=='#' ){
@@ -515,10 +534,11 @@
534 int nArg = 0;
535 const char **azArg = 0;
536 int i, k;
537 int nErr = 0;
538 char *acType;
539 int nInit = 0;
540
541 szFName = token_length(zFCall, &eToken, &ln);
542 zStart = next_non_whitespace(zFCall+szFName, &len, &eToken);
543 assert( zStart[0]=='(' && len==1 );
544 len = distance_to(zStart+1, ')');
@@ -545,21 +565,34 @@
565 nErr++;
566 }else{
567 const char *zFmt = azArg[fmtArg-1];
568 const char *zOverride = strstr(zFmt, "/*works-like:");
569 if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1;
570 if( fmtFlags & FMT_LIT ){
571 if( !is_string_lit(zFmt) ){
572 printf("%s:%d: argument %d to %.*s() should be a string literal\n",
573 zFilename, lnFCall, fmtArg, szFName, zFCall);
574 nErr++;
575 }
576 }else if( !is_string_lit(zFmt) ){
577 printf("%s:%d: %.*s() has non-constant format on arg[%d]\n",
578 zFilename, lnFCall, szFName, zFCall, fmtArg-1);
579 nErr++;
580 }else if( (k = formatArgCount(zFmt, nArg, acType, &nInit))>=0
581 && nArg!=fmtArg+k ){
582 printf("%s:%d: too %s arguments to %.*s() "
583 "- got %d and expected %d\n",
584 zFilename, lnFCall, (nArg<fmtArg+k ? "few" : "many"),
585 szFName, zFCall, nArg, fmtArg+k);
586 nErr++;
587 }else if( (fmtFlags & FMT_PX)!=0 ){
588 if( nInit==0 ){
589 printf("%s:%d: format string on %.*s() should have"
590 " an ASCII character prefix\n",
591 zFilename, lnFCall, szFName, zFCall);
592 nErr++;
593 }
594 }else if( (fmtFlags & FMT_SAFE)==0 ){
595 for(i=0; i<nArg && i<k; i++){
596 if( (acType[i]=='s' || acType[i]=='z' || acType[i]=='b') ){
597 const char *zExpr = azArg[fmtArg+i];
598 if( never_safe(zExpr) ){
599
+9 -4
--- src/db.c
+++ src/db.c
@@ -3321,10 +3321,15 @@
33213321
void db_lset_int(const char *zName, int value){
33223322
db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
33233323
}
33243324
33253325
/* Va-args versions of db_get(), db_set(), and db_unset()
3326
+**
3327
+** codecheck1.c verifies that the format string for db_set_mprintf()
3328
+** and db_unset_mprintf() begins with an ASCII character prefix. We
3329
+** don't want that format string to begin with %s or %d as that might
3330
+** allow an injection attack to set or overwrite arbitrary settings.
33263331
*/
33273332
char *db_get_mprintf(const char *zDefault, const char *zFormat, ...){
33283333
va_list ap;
33293334
char *zName;
33303335
char *zResult;
@@ -3339,20 +3344,20 @@
33393344
va_list ap;
33403345
char *zName;
33413346
va_start(ap, zFormat);
33423347
zName = vmprintf(zFormat, ap);
33433348
va_end(ap);
3344
- db_set(zName, zNew, iGlobal);
3349
+ db_set(zName/*works-like:"x"*/, zNew, iGlobal);
33453350
fossil_free(zName);
33463351
}
33473352
void db_unset_mprintf(int iGlobal, const char *zFormat, ...){
33483353
va_list ap;
33493354
char *zName;
33503355
va_start(ap, zFormat);
33513356
zName = vmprintf(zFormat, ap);
33523357
va_end(ap);
3353
- db_unset(zName, iGlobal);
3358
+ db_unset(zName/*works-like:"x"*/, iGlobal);
33543359
fossil_free(zName);
33553360
}
33563361
33573362
33583363
@@ -4413,14 +4418,14 @@
44134418
}
44144419
if( globalFlag && isManifest ){
44154420
fossil_fatal("cannot set 'manifest' globally");
44164421
}
44174422
if( unsetFlag ){
4418
- db_unset(pSetting->name, globalFlag);
4423
+ db_unset(pSetting->name/*works-like:"x"*/, globalFlag);
44194424
}else{
44204425
db_protect_only(PROTECT_NONE);
4421
- db_set(pSetting->name, g.argv[3], globalFlag);
4426
+ db_set(pSetting->name/*works-like:"x"*/, g.argv[3], globalFlag);
44224427
db_protect_pop();
44234428
}
44244429
if( isManifest && g.localOpen ){
44254430
manifest_to_disk(db_lget_int("checkout", 0));
44264431
}
44274432
--- src/db.c
+++ src/db.c
@@ -3321,10 +3321,15 @@
3321 void db_lset_int(const char *zName, int value){
3322 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
3323 }
3324
3325 /* Va-args versions of db_get(), db_set(), and db_unset()
 
 
 
 
 
3326 */
3327 char *db_get_mprintf(const char *zDefault, const char *zFormat, ...){
3328 va_list ap;
3329 char *zName;
3330 char *zResult;
@@ -3339,20 +3344,20 @@
3339 va_list ap;
3340 char *zName;
3341 va_start(ap, zFormat);
3342 zName = vmprintf(zFormat, ap);
3343 va_end(ap);
3344 db_set(zName, zNew, iGlobal);
3345 fossil_free(zName);
3346 }
3347 void db_unset_mprintf(int iGlobal, const char *zFormat, ...){
3348 va_list ap;
3349 char *zName;
3350 va_start(ap, zFormat);
3351 zName = vmprintf(zFormat, ap);
3352 va_end(ap);
3353 db_unset(zName, iGlobal);
3354 fossil_free(zName);
3355 }
3356
3357
3358
@@ -4413,14 +4418,14 @@
4413 }
4414 if( globalFlag && isManifest ){
4415 fossil_fatal("cannot set 'manifest' globally");
4416 }
4417 if( unsetFlag ){
4418 db_unset(pSetting->name, globalFlag);
4419 }else{
4420 db_protect_only(PROTECT_NONE);
4421 db_set(pSetting->name, g.argv[3], globalFlag);
4422 db_protect_pop();
4423 }
4424 if( isManifest && g.localOpen ){
4425 manifest_to_disk(db_lget_int("checkout", 0));
4426 }
4427
--- src/db.c
+++ src/db.c
@@ -3321,10 +3321,15 @@
3321 void db_lset_int(const char *zName, int value){
3322 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
3323 }
3324
3325 /* Va-args versions of db_get(), db_set(), and db_unset()
3326 **
3327 ** codecheck1.c verifies that the format string for db_set_mprintf()
3328 ** and db_unset_mprintf() begins with an ASCII character prefix. We
3329 ** don't want that format string to begin with %s or %d as that might
3330 ** allow an injection attack to set or overwrite arbitrary settings.
3331 */
3332 char *db_get_mprintf(const char *zDefault, const char *zFormat, ...){
3333 va_list ap;
3334 char *zName;
3335 char *zResult;
@@ -3339,20 +3344,20 @@
3344 va_list ap;
3345 char *zName;
3346 va_start(ap, zFormat);
3347 zName = vmprintf(zFormat, ap);
3348 va_end(ap);
3349 db_set(zName/*works-like:"x"*/, zNew, iGlobal);
3350 fossil_free(zName);
3351 }
3352 void db_unset_mprintf(int iGlobal, const char *zFormat, ...){
3353 va_list ap;
3354 char *zName;
3355 va_start(ap, zFormat);
3356 zName = vmprintf(zFormat, ap);
3357 va_end(ap);
3358 db_unset(zName/*works-like:"x"*/, iGlobal);
3359 fossil_free(zName);
3360 }
3361
3362
3363
@@ -4413,14 +4418,14 @@
4418 }
4419 if( globalFlag && isManifest ){
4420 fossil_fatal("cannot set 'manifest' globally");
4421 }
4422 if( unsetFlag ){
4423 db_unset(pSetting->name/*works-like:"x"*/, globalFlag);
4424 }else{
4425 db_protect_only(PROTECT_NONE);
4426 db_set(pSetting->name/*works-like:"x"*/, g.argv[3], globalFlag);
4427 db_protect_pop();
4428 }
4429 if( isManifest && g.localOpen ){
4430 manifest_to_disk(db_lget_int("checkout", 0));
4431 }
4432
+1 -3
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -437,13 +437,11 @@
437437
*/
438438
LOCAL void ssl_remember_certificate_exception(
439439
UrlData *pUrlData,
440440
const char *zHash
441441
){
442
- char *zName = mprintf("cert:%s", pUrlData->name);
443
- db_set(zName, zHash, 1);
444
- fossil_free(zName);
442
+ db_set_mprintf(zHash, 1, "cert:%s", pUrlData->name);
445443
}
446444
447445
/*
448446
** Return true if the there exists a certificate exception for
449447
** pUrlData->name that matches the hash.
450448
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -437,13 +437,11 @@
437 */
438 LOCAL void ssl_remember_certificate_exception(
439 UrlData *pUrlData,
440 const char *zHash
441 ){
442 char *zName = mprintf("cert:%s", pUrlData->name);
443 db_set(zName, zHash, 1);
444 fossil_free(zName);
445 }
446
447 /*
448 ** Return true if the there exists a certificate exception for
449 ** pUrlData->name that matches the hash.
450
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -437,13 +437,11 @@
437 */
438 LOCAL void ssl_remember_certificate_exception(
439 UrlData *pUrlData,
440 const char *zHash
441 ){
442 db_set_mprintf(zHash, 1, "cert:%s", pUrlData->name);
 
 
443 }
444
445 /*
446 ** Return true if the there exists a certificate exception for
447 ** pUrlData->name that matches the hash.
448
+1 -1
--- src/search.c
+++ src/search.c
@@ -1930,11 +1930,11 @@
19301930
const char *zCtrl;
19311931
if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
19321932
zCtrl = g.argv[3];
19331933
for(j=0; j<count(aSetng); j++){
19341934
if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
1935
- db_set_int(aSetng[j].zSetting, iCmd-3, 0);
1935
+ db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
19361936
}
19371937
}
19381938
}
19391939
if( iCmd==5 ){
19401940
if( g.argc<4 ) usage("porter ON/OFF");
19411941
--- src/search.c
+++ src/search.c
@@ -1930,11 +1930,11 @@
1930 const char *zCtrl;
1931 if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
1932 zCtrl = g.argv[3];
1933 for(j=0; j<count(aSetng); j++){
1934 if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
1935 db_set_int(aSetng[j].zSetting, iCmd-3, 0);
1936 }
1937 }
1938 }
1939 if( iCmd==5 ){
1940 if( g.argc<4 ) usage("porter ON/OFF");
1941
--- src/search.c
+++ src/search.c
@@ -1930,11 +1930,11 @@
1930 const char *zCtrl;
1931 if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
1932 zCtrl = g.argv[3];
1933 for(j=0; j<count(aSetng); j++){
1934 if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
1935 db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
1936 }
1937 }
1938 }
1939 if( iCmd==5 ){
1940 if( g.argc<4 ) usage("porter ON/OFF");
1941
+15 -15
--- src/setup.c
+++ src/setup.c
@@ -186,13 +186,13 @@
186186
/*
187187
** Generate a checkbox for an attribute.
188188
*/
189189
void onoff_attribute(
190190
const char *zLabel, /* The text label on the checkbox */
191
- const char *zVar, /* The corresponding row in the VAR table */
191
+ const char *zVar, /* The corresponding row in the CONFIG table */
192192
const char *zQParm, /* The query parameter */
193
- int dfltVal, /* Default value if VAR table entry does not exist */
193
+ int dfltVal, /* Default value if CONFIG table entry does not exist */
194194
int disabled /* 1 if disabled */
195195
){
196196
const char *zQ = P(zQParm);
197197
int iVal = db_get_boolean(zVar, dfltVal);
198198
if( zQ==0 && !disabled && P("submit") ){
@@ -201,11 +201,11 @@
201201
if( zQ ){
202202
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
203203
if( iQ!=iVal ){
204204
login_verify_csrf_secret();
205205
db_protect_only(PROTECT_NONE);
206
- db_set(zVar, iQ ? "1" : "0", 0);
206
+ db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
207207
db_protect_pop();
208208
setup_incr_cfgcnt();
209209
admin_log("Set option [%q] to [%q].",
210210
zVar, iQ ? "on" : "off");
211211
iVal = iQ;
@@ -226,23 +226,23 @@
226226
** Generate an entry box for an attribute.
227227
*/
228228
void entry_attribute(
229229
const char *zLabel, /* The text label on the entry box */
230230
int width, /* Width of the entry box */
231
- const char *zVar, /* The corresponding row in the VAR table */
231
+ const char *zVar, /* The corresponding row in the CONFIG table */
232232
const char *zQParm, /* The query parameter */
233
- const char *zDflt, /* Default value if VAR table entry does not exist */
233
+ const char *zDflt, /* Default value if CONFIG table entry does not exist */
234234
int disabled /* 1 if disabled */
235235
){
236236
const char *zVal = db_get(zVar, zDflt);
237237
const char *zQ = P(zQParm);
238238
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
239239
const int nZQ = (int)strlen(zQ);
240240
login_verify_csrf_secret();
241241
setup_incr_cfgcnt();
242242
db_protect_only(PROTECT_NONE);
243
- db_set(zVar, zQ, 0);
243
+ db_set(zVar/*works-like:"x"*/, zQ, 0);
244244
db_protect_pop();
245245
admin_log("Set entry_attribute %Q to: %.*s%s",
246246
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
247247
zVal = zQ;
248248
}
@@ -259,22 +259,22 @@
259259
*/
260260
const char *textarea_attribute(
261261
const char *zLabel, /* The text label on the textarea */
262262
int rows, /* Rows in the textarea */
263263
int cols, /* Columns in the textarea */
264
- const char *zVar, /* The corresponding row in the VAR table */
264
+ const char *zVar, /* The corresponding row in the CONFIG table */
265265
const char *zQP, /* The query parameter */
266
- const char *zDflt, /* Default value if VAR table entry does not exist */
266
+ const char *zDflt, /* Default value if CONFIG table entry does not exist */
267267
int disabled /* 1 if the textarea should not be editable */
268268
){
269269
const char *z = db_get(zVar, zDflt);
270270
const char *zQ = P(zQP);
271271
if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
272272
const int nZQ = (int)strlen(zQ);
273273
login_verify_csrf_secret();
274274
db_protect_only(PROTECT_NONE);
275
- db_set(zVar, zQ, 0);
275
+ db_set(zVar/*works-like:"x"*/, zQ, 0);
276276
db_protect_pop();
277277
setup_incr_cfgcnt();
278278
admin_log("Set textarea_attribute %Q to: %.*s%s",
279279
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
280280
z = zQ;
@@ -296,13 +296,13 @@
296296
/*
297297
** Generate a text box for an attribute.
298298
*/
299299
void multiple_choice_attribute(
300300
const char *zLabel, /* The text label on the menu */
301
- const char *zVar, /* The corresponding row in the VAR table */
301
+ const char *zVar, /* The corresponding row in the CONFIG table */
302302
const char *zQP, /* The query parameter */
303
- const char *zDflt, /* Default value if VAR table entry does not exist */
303
+ const char *zDflt, /* Default value if CONFIG table entry does not exist */
304304
int nChoice, /* Number of choices */
305305
const char *const *azChoice /* Choices in pairs (VAR value, Display) */
306306
){
307307
const char *z = db_get(zVar, zDflt);
308308
const char *zQ = P(zQP);
@@ -309,11 +309,11 @@
309309
int i;
310310
if( zQ && fossil_strcmp(zQ,z)!=0){
311311
const int nZQ = (int)strlen(zQ);
312312
login_verify_csrf_secret();
313313
db_unprotect(PROTECT_ALL);
314
- db_set(zVar, zQ, 0);
314
+ db_set(zVar/*works-like:"x"*/, zQ, 0);
315315
setup_incr_cfgcnt();
316316
db_protect_pop();
317317
admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
318318
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
319319
z = zQ;
@@ -899,11 +899,11 @@
899899
for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
900900
if( pSet->width==0 ){
901901
int hasVersionableValue = pSet->versionable &&
902902
(db_get_versioned(pSet->name, NULL)!=0);
903903
onoff_attribute("", pSet->name,
904
- pSet->var!=0 ? pSet->var : pSet->name,
904
+ pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
905905
is_truth(pSet->def), hasVersionableValue);
906906
@ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
907907
if( pSet->versionable ){
908908
@ (v)<br />
909909
} else {
@@ -925,11 +925,11 @@
925925
} else {
926926
@
927927
}
928928
@</td><td>
929929
entry_attribute("", /*pSet->width*/ 25, pSet->name,
930
- pSet->var!=0 ? pSet->var : pSet->name,
930
+ pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
931931
(char*)pSet->def, hasVersionableValue);
932932
@</td></tr>
933933
}
934934
}
935935
@</table>
@@ -942,11 +942,11 @@
942942
@ (v)<br />
943943
} else {
944944
@ <br />
945945
}
946946
textarea_attribute("", /*rows*/ 2, /*cols*/ 35, pSet->name,
947
- pSet->var!=0 ? pSet->var : pSet->name,
947
+ pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
948948
(char*)pSet->def, hasVersionableValue);
949949
@<br />
950950
}
951951
}
952952
@ </td></tr></table>
953953
--- src/setup.c
+++ src/setup.c
@@ -186,13 +186,13 @@
186 /*
187 ** Generate a checkbox for an attribute.
188 */
189 void onoff_attribute(
190 const char *zLabel, /* The text label on the checkbox */
191 const char *zVar, /* The corresponding row in the VAR table */
192 const char *zQParm, /* The query parameter */
193 int dfltVal, /* Default value if VAR table entry does not exist */
194 int disabled /* 1 if disabled */
195 ){
196 const char *zQ = P(zQParm);
197 int iVal = db_get_boolean(zVar, dfltVal);
198 if( zQ==0 && !disabled && P("submit") ){
@@ -201,11 +201,11 @@
201 if( zQ ){
202 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
203 if( iQ!=iVal ){
204 login_verify_csrf_secret();
205 db_protect_only(PROTECT_NONE);
206 db_set(zVar, iQ ? "1" : "0", 0);
207 db_protect_pop();
208 setup_incr_cfgcnt();
209 admin_log("Set option [%q] to [%q].",
210 zVar, iQ ? "on" : "off");
211 iVal = iQ;
@@ -226,23 +226,23 @@
226 ** Generate an entry box for an attribute.
227 */
228 void entry_attribute(
229 const char *zLabel, /* The text label on the entry box */
230 int width, /* Width of the entry box */
231 const char *zVar, /* The corresponding row in the VAR table */
232 const char *zQParm, /* The query parameter */
233 const char *zDflt, /* Default value if VAR table entry does not exist */
234 int disabled /* 1 if disabled */
235 ){
236 const char *zVal = db_get(zVar, zDflt);
237 const char *zQ = P(zQParm);
238 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
239 const int nZQ = (int)strlen(zQ);
240 login_verify_csrf_secret();
241 setup_incr_cfgcnt();
242 db_protect_only(PROTECT_NONE);
243 db_set(zVar, zQ, 0);
244 db_protect_pop();
245 admin_log("Set entry_attribute %Q to: %.*s%s",
246 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
247 zVal = zQ;
248 }
@@ -259,22 +259,22 @@
259 */
260 const char *textarea_attribute(
261 const char *zLabel, /* The text label on the textarea */
262 int rows, /* Rows in the textarea */
263 int cols, /* Columns in the textarea */
264 const char *zVar, /* The corresponding row in the VAR table */
265 const char *zQP, /* The query parameter */
266 const char *zDflt, /* Default value if VAR table entry does not exist */
267 int disabled /* 1 if the textarea should not be editable */
268 ){
269 const char *z = db_get(zVar, zDflt);
270 const char *zQ = P(zQP);
271 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
272 const int nZQ = (int)strlen(zQ);
273 login_verify_csrf_secret();
274 db_protect_only(PROTECT_NONE);
275 db_set(zVar, zQ, 0);
276 db_protect_pop();
277 setup_incr_cfgcnt();
278 admin_log("Set textarea_attribute %Q to: %.*s%s",
279 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
280 z = zQ;
@@ -296,13 +296,13 @@
296 /*
297 ** Generate a text box for an attribute.
298 */
299 void multiple_choice_attribute(
300 const char *zLabel, /* The text label on the menu */
301 const char *zVar, /* The corresponding row in the VAR table */
302 const char *zQP, /* The query parameter */
303 const char *zDflt, /* Default value if VAR table entry does not exist */
304 int nChoice, /* Number of choices */
305 const char *const *azChoice /* Choices in pairs (VAR value, Display) */
306 ){
307 const char *z = db_get(zVar, zDflt);
308 const char *zQ = P(zQP);
@@ -309,11 +309,11 @@
309 int i;
310 if( zQ && fossil_strcmp(zQ,z)!=0){
311 const int nZQ = (int)strlen(zQ);
312 login_verify_csrf_secret();
313 db_unprotect(PROTECT_ALL);
314 db_set(zVar, zQ, 0);
315 setup_incr_cfgcnt();
316 db_protect_pop();
317 admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
318 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
319 z = zQ;
@@ -899,11 +899,11 @@
899 for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
900 if( pSet->width==0 ){
901 int hasVersionableValue = pSet->versionable &&
902 (db_get_versioned(pSet->name, NULL)!=0);
903 onoff_attribute("", pSet->name,
904 pSet->var!=0 ? pSet->var : pSet->name,
905 is_truth(pSet->def), hasVersionableValue);
906 @ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
907 if( pSet->versionable ){
908 @ (v)<br />
909 } else {
@@ -925,11 +925,11 @@
925 } else {
926 @
927 }
928 @</td><td>
929 entry_attribute("", /*pSet->width*/ 25, pSet->name,
930 pSet->var!=0 ? pSet->var : pSet->name,
931 (char*)pSet->def, hasVersionableValue);
932 @</td></tr>
933 }
934 }
935 @</table>
@@ -942,11 +942,11 @@
942 @ (v)<br />
943 } else {
944 @ <br />
945 }
946 textarea_attribute("", /*rows*/ 2, /*cols*/ 35, pSet->name,
947 pSet->var!=0 ? pSet->var : pSet->name,
948 (char*)pSet->def, hasVersionableValue);
949 @<br />
950 }
951 }
952 @ </td></tr></table>
953
--- src/setup.c
+++ src/setup.c
@@ -186,13 +186,13 @@
186 /*
187 ** Generate a checkbox for an attribute.
188 */
189 void onoff_attribute(
190 const char *zLabel, /* The text label on the checkbox */
191 const char *zVar, /* The corresponding row in the CONFIG table */
192 const char *zQParm, /* The query parameter */
193 int dfltVal, /* Default value if CONFIG table entry does not exist */
194 int disabled /* 1 if disabled */
195 ){
196 const char *zQ = P(zQParm);
197 int iVal = db_get_boolean(zVar, dfltVal);
198 if( zQ==0 && !disabled && P("submit") ){
@@ -201,11 +201,11 @@
201 if( zQ ){
202 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
203 if( iQ!=iVal ){
204 login_verify_csrf_secret();
205 db_protect_only(PROTECT_NONE);
206 db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
207 db_protect_pop();
208 setup_incr_cfgcnt();
209 admin_log("Set option [%q] to [%q].",
210 zVar, iQ ? "on" : "off");
211 iVal = iQ;
@@ -226,23 +226,23 @@
226 ** Generate an entry box for an attribute.
227 */
228 void entry_attribute(
229 const char *zLabel, /* The text label on the entry box */
230 int width, /* Width of the entry box */
231 const char *zVar, /* The corresponding row in the CONFIG table */
232 const char *zQParm, /* The query parameter */
233 const char *zDflt, /* Default value if CONFIG table entry does not exist */
234 int disabled /* 1 if disabled */
235 ){
236 const char *zVal = db_get(zVar, zDflt);
237 const char *zQ = P(zQParm);
238 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
239 const int nZQ = (int)strlen(zQ);
240 login_verify_csrf_secret();
241 setup_incr_cfgcnt();
242 db_protect_only(PROTECT_NONE);
243 db_set(zVar/*works-like:"x"*/, zQ, 0);
244 db_protect_pop();
245 admin_log("Set entry_attribute %Q to: %.*s%s",
246 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
247 zVal = zQ;
248 }
@@ -259,22 +259,22 @@
259 */
260 const char *textarea_attribute(
261 const char *zLabel, /* The text label on the textarea */
262 int rows, /* Rows in the textarea */
263 int cols, /* Columns in the textarea */
264 const char *zVar, /* The corresponding row in the CONFIG table */
265 const char *zQP, /* The query parameter */
266 const char *zDflt, /* Default value if CONFIG table entry does not exist */
267 int disabled /* 1 if the textarea should not be editable */
268 ){
269 const char *z = db_get(zVar, zDflt);
270 const char *zQ = P(zQP);
271 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
272 const int nZQ = (int)strlen(zQ);
273 login_verify_csrf_secret();
274 db_protect_only(PROTECT_NONE);
275 db_set(zVar/*works-like:"x"*/, zQ, 0);
276 db_protect_pop();
277 setup_incr_cfgcnt();
278 admin_log("Set textarea_attribute %Q to: %.*s%s",
279 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
280 z = zQ;
@@ -296,13 +296,13 @@
296 /*
297 ** Generate a text box for an attribute.
298 */
299 void multiple_choice_attribute(
300 const char *zLabel, /* The text label on the menu */
301 const char *zVar, /* The corresponding row in the CONFIG table */
302 const char *zQP, /* The query parameter */
303 const char *zDflt, /* Default value if CONFIG table entry does not exist */
304 int nChoice, /* Number of choices */
305 const char *const *azChoice /* Choices in pairs (VAR value, Display) */
306 ){
307 const char *z = db_get(zVar, zDflt);
308 const char *zQ = P(zQP);
@@ -309,11 +309,11 @@
309 int i;
310 if( zQ && fossil_strcmp(zQ,z)!=0){
311 const int nZQ = (int)strlen(zQ);
312 login_verify_csrf_secret();
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",
318 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
319 z = zQ;
@@ -899,11 +899,11 @@
899 for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
900 if( pSet->width==0 ){
901 int hasVersionableValue = pSet->versionable &&
902 (db_get_versioned(pSet->name, NULL)!=0);
903 onoff_attribute("", pSet->name,
904 pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
905 is_truth(pSet->def), hasVersionableValue);
906 @ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
907 if( pSet->versionable ){
908 @ (v)<br />
909 } else {
@@ -925,11 +925,11 @@
925 } else {
926 @
927 }
928 @</td><td>
929 entry_attribute("", /*pSet->width*/ 25, pSet->name,
930 pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
931 (char*)pSet->def, hasVersionableValue);
932 @</td></tr>
933 }
934 }
935 @</table>
@@ -942,11 +942,11 @@
942 @ (v)<br />
943 } else {
944 @ <br />
945 }
946 textarea_attribute("", /*rows*/ 2, /*cols*/ 35, pSet->name,
947 pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
948 (char*)pSet->def, hasVersionableValue);
949 @<br />
950 }
951 }
952 @ </td></tr></table>
953
+3 -5
--- src/skins.c
+++ src/skins.c
@@ -789,11 +789,10 @@
789789
const char *zBasis; /* The baseline file */
790790
const char *zOrig; /* Original content prior to editing */
791791
const char *zContent; /* Content after editing */
792792
const char *zDflt; /* Default content */
793793
char *zDraft; /* Which draft: "draft%d" */
794
- char *zKey; /* CONFIG table key name: "draft%d-%s" */
795794
char *zTitle; /* Title of this page */
796795
const char *zFile; /* One of "css", "footer", "header", "details" */
797796
int iSkin; /* draft number. 1..9 */
798797
int ii; /* Index in aSkinAttr[] of this file */
799798
int j; /* Loop counter */
@@ -827,15 +826,14 @@
827826
/* figure out which file is to be edited */
828827
ii = atoi(PD("w","0"));
829828
if( ii<0 || ii>count(aSkinAttr) ) ii = 0;
830829
zFile = aSkinAttr[ii].zFile;
831830
zDraft = mprintf("draft%d", iSkin);
832
- zKey = mprintf("draft%d-%s", iSkin, zFile);
833831
zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
834832
zBasis = PD("basis","current");
835833
zDflt = skin_file_content(zBasis, zFile);
836
- zOrig = db_get(zKey, zDflt);
834
+ zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
837835
zContent = PD(zFile,zOrig);
838836
if( P("revert")!=0 && cgi_csrf_safe(0) ){
839837
zContent = zDflt;
840838
isRevert = 1;
841839
}
@@ -851,11 +849,11 @@
851849
login_insert_csrf_secret();
852850
@ <input type='hidden' name='w' value='%d(ii)'>
853851
@ <input type='hidden' name='sk' value='%d(iSkin)'>
854852
@ <h2>Edit %s(zTitle):</h2>
855853
if( P("submit") && cgi_csrf_safe(0) && strcmp(zOrig,zContent)!=0 ){
856
- db_set(zKey, zContent, 0);
854
+ db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
857855
}
858856
@ <textarea name="%s(zFile)" rows="10" cols="80">\
859857
@ %h(zContent)</textarea>
860858
@ <br />
861859
@ <input type="submit" name="submit" value="Apply Changes" />
@@ -942,11 +940,11 @@
942940
}
943941
944942
/* Publish draft iSkin */
945943
for(i=0; i<count(azSkinFile); i++){
946944
char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]);
947
- db_set(azSkinFile[i], zNew, 0);
945
+ db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0);
948946
}
949947
}
950948
951949
/*
952950
** WEBPAGE: setup_skin
953951
--- src/skins.c
+++ src/skins.c
@@ -789,11 +789,10 @@
789 const char *zBasis; /* The baseline file */
790 const char *zOrig; /* Original content prior to editing */
791 const char *zContent; /* Content after editing */
792 const char *zDflt; /* Default content */
793 char *zDraft; /* Which draft: "draft%d" */
794 char *zKey; /* CONFIG table key name: "draft%d-%s" */
795 char *zTitle; /* Title of this page */
796 const char *zFile; /* One of "css", "footer", "header", "details" */
797 int iSkin; /* draft number. 1..9 */
798 int ii; /* Index in aSkinAttr[] of this file */
799 int j; /* Loop counter */
@@ -827,15 +826,14 @@
827 /* figure out which file is to be edited */
828 ii = atoi(PD("w","0"));
829 if( ii<0 || ii>count(aSkinAttr) ) ii = 0;
830 zFile = aSkinAttr[ii].zFile;
831 zDraft = mprintf("draft%d", iSkin);
832 zKey = mprintf("draft%d-%s", iSkin, zFile);
833 zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
834 zBasis = PD("basis","current");
835 zDflt = skin_file_content(zBasis, zFile);
836 zOrig = db_get(zKey, zDflt);
837 zContent = PD(zFile,zOrig);
838 if( P("revert")!=0 && cgi_csrf_safe(0) ){
839 zContent = zDflt;
840 isRevert = 1;
841 }
@@ -851,11 +849,11 @@
851 login_insert_csrf_secret();
852 @ <input type='hidden' name='w' value='%d(ii)'>
853 @ <input type='hidden' name='sk' value='%d(iSkin)'>
854 @ <h2>Edit %s(zTitle):</h2>
855 if( P("submit") && cgi_csrf_safe(0) && strcmp(zOrig,zContent)!=0 ){
856 db_set(zKey, zContent, 0);
857 }
858 @ <textarea name="%s(zFile)" rows="10" cols="80">\
859 @ %h(zContent)</textarea>
860 @ <br />
861 @ <input type="submit" name="submit" value="Apply Changes" />
@@ -942,11 +940,11 @@
942 }
943
944 /* Publish draft iSkin */
945 for(i=0; i<count(azSkinFile); i++){
946 char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]);
947 db_set(azSkinFile[i], zNew, 0);
948 }
949 }
950
951 /*
952 ** WEBPAGE: setup_skin
953
--- src/skins.c
+++ src/skins.c
@@ -789,11 +789,10 @@
789 const char *zBasis; /* The baseline file */
790 const char *zOrig; /* Original content prior to editing */
791 const char *zContent; /* Content after editing */
792 const char *zDflt; /* Default content */
793 char *zDraft; /* Which draft: "draft%d" */
 
794 char *zTitle; /* Title of this page */
795 const char *zFile; /* One of "css", "footer", "header", "details" */
796 int iSkin; /* draft number. 1..9 */
797 int ii; /* Index in aSkinAttr[] of this file */
798 int j; /* Loop counter */
@@ -827,15 +826,14 @@
826 /* figure out which file is to be edited */
827 ii = atoi(PD("w","0"));
828 if( ii<0 || ii>count(aSkinAttr) ) ii = 0;
829 zFile = aSkinAttr[ii].zFile;
830 zDraft = mprintf("draft%d", iSkin);
 
831 zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
832 zBasis = PD("basis","current");
833 zDflt = skin_file_content(zBasis, zFile);
834 zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
835 zContent = PD(zFile,zOrig);
836 if( P("revert")!=0 && cgi_csrf_safe(0) ){
837 zContent = zDflt;
838 isRevert = 1;
839 }
@@ -851,11 +849,11 @@
849 login_insert_csrf_secret();
850 @ <input type='hidden' name='w' value='%d(ii)'>
851 @ <input type='hidden' name='sk' value='%d(iSkin)'>
852 @ <h2>Edit %s(zTitle):</h2>
853 if( P("submit") && cgi_csrf_safe(0) && strcmp(zOrig,zContent)!=0 ){
854 db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
855 }
856 @ <textarea name="%s(zFile)" rows="10" cols="80">\
857 @ %h(zContent)</textarea>
858 @ <br />
859 @ <input type="submit" name="submit" value="Apply Changes" />
@@ -942,11 +940,11 @@
940 }
941
942 /* Publish draft iSkin */
943 for(i=0; i<count(azSkinFile); i++){
944 char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]);
945 db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0);
946 }
947 }
948
949 /*
950 ** WEBPAGE: setup_skin
951
+2 -2
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -136,20 +136,20 @@
136136
}
137137
style_set_current_feature("tktsetup");
138138
style_header("Edit %s", zTitle);
139139
if( P("clear")!=0 ){
140140
login_verify_csrf_secret();
141
- db_unset(zDbField, 0);
141
+ db_unset(zDbField/*works-like:"x"*/, 0);
142142
if( xRebuild ) xRebuild();
143143
cgi_redirect("tktsetup");
144144
}else if( isSubmit ){
145145
char *zErr = 0;
146146
login_verify_csrf_secret();
147147
if( xText && (zErr = xText(z))!=0 ){
148148
@ <p class="tktsetupError">ERROR: %h(zErr)</p>
149149
}else{
150
- db_set(zDbField, z, 0);
150
+ db_set(zDbField/*works-like:"x"*/, z, 0);
151151
if( xRebuild ) xRebuild();
152152
cgi_redirect("tktsetup");
153153
}
154154
}
155155
@ <form action="%R/%s(g.zPath)" method="post"><div>
156156
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -136,20 +136,20 @@
136 }
137 style_set_current_feature("tktsetup");
138 style_header("Edit %s", zTitle);
139 if( P("clear")!=0 ){
140 login_verify_csrf_secret();
141 db_unset(zDbField, 0);
142 if( xRebuild ) xRebuild();
143 cgi_redirect("tktsetup");
144 }else if( isSubmit ){
145 char *zErr = 0;
146 login_verify_csrf_secret();
147 if( xText && (zErr = xText(z))!=0 ){
148 @ <p class="tktsetupError">ERROR: %h(zErr)</p>
149 }else{
150 db_set(zDbField, z, 0);
151 if( xRebuild ) xRebuild();
152 cgi_redirect("tktsetup");
153 }
154 }
155 @ <form action="%R/%s(g.zPath)" method="post"><div>
156
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -136,20 +136,20 @@
136 }
137 style_set_current_feature("tktsetup");
138 style_header("Edit %s", zTitle);
139 if( P("clear")!=0 ){
140 login_verify_csrf_secret();
141 db_unset(zDbField/*works-like:"x"*/, 0);
142 if( xRebuild ) xRebuild();
143 cgi_redirect("tktsetup");
144 }else if( isSubmit ){
145 char *zErr = 0;
146 login_verify_csrf_secret();
147 if( xText && (zErr = xText(z))!=0 ){
148 @ <p class="tktsetupError">ERROR: %h(zErr)</p>
149 }else{
150 db_set(zDbField/*works-like:"x"*/, z, 0);
151 if( xRebuild ) xRebuild();
152 cgi_redirect("tktsetup");
153 }
154 }
155 @ <form action="%R/%s(g.zPath)" method="post"><div>
156
+2 -2
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -120,20 +120,20 @@
120120
}
121121
style_set_current_feature("xfersetup");
122122
style_header("Edit %s", zTitle);
123123
if( P("clear")!=0 ){
124124
login_verify_csrf_secret();
125
- db_unset(zDbField, 0);
125
+ db_unset(zDbField/*works-like:"x"*/, 0);
126126
if( xRebuild ) xRebuild();
127127
z = zDfltValue;
128128
}else if( isSubmit ){
129129
char *zErr = 0;
130130
login_verify_csrf_secret();
131131
if( xText && (zErr = xText(z))!=0 ){
132132
@ <p class="xfersetupError">ERROR: %h(zErr)</p>
133133
}else{
134
- db_set(zDbField, z, 0);
134
+ db_set(zDbField/*works-like:"x"*/, z, 0);
135135
if( xRebuild ) xRebuild();
136136
cgi_redirect("xfersetup");
137137
}
138138
}
139139
@ <form action="%R/%s(g.zPath)" method="post"><div>
140140
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -120,20 +120,20 @@
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, 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, z, 0);
135 if( xRebuild ) xRebuild();
136 cgi_redirect("xfersetup");
137 }
138 }
139 @ <form action="%R/%s(g.zPath)" method="post"><div>
140
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -120,20 +120,20 @@
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 cgi_redirect("xfersetup");
137 }
138 }
139 @ <form action="%R/%s(g.zPath)" method="post"><div>
140

Keyboard Shortcuts

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