Fossil SCM

Additional checks to ensure that db_set() and db_set_int() do not modify a sensitive setting unless PROTECT_BASELINE is disabled.

drh 2020-08-21 18:32 sec2020
Commit ccdb5a9bb8b7a188e8c466a800ab9f9dff69bb5c10a8e6b5ddbd23b11143ddd9
2 files changed +40 -16 +6
+40 -16
--- src/db.c
+++ src/db.c
@@ -139,11 +139,11 @@
139139
const char *zAuthName; /* Name of the authorizer */
140140
int bProtectTriggers; /* True if protection triggers already exist */
141141
int nProtect; /* Slots of aProtect used */
142142
unsigned aProtect[10]; /* Saved values of protectMask */
143143
} db = {
144
- PROTECT_USER|PROTECT_CONFIG, /* protectMask */
144
+ PROTECT_USER|PROTECT_CONFIG|PROTECT_BASELINE, /* protectMask */
145145
0, 0, 0, 0, 0, 0, };
146146
147147
/*
148148
** Arrange for the given file to be deleted on a failure.
149149
*/
@@ -338,11 +338,12 @@
338338
*/
339339
#define PROTECT_USER 0x01 /* USER table */
340340
#define PROTECT_CONFIG 0x02 /* CONFIG and GLOBAL_CONFIG tables */
341341
#define PROTECT_SENSITIVE 0x04 /* Sensitive and/or global settings */
342342
#define PROTECT_READONLY 0x08 /* everything except TEMP tables */
343
-#define PROTECT_ALL 0x0f /* All of the above */
343
+#define PROTECT_BASELINE 0x10 /* protection system is working */
344
+#define PROTECT_ALL 0x1f /* All of the above */
344345
#define PROTECT_NONE 0x00 /* Nothing. Everything is open */
345346
#endif /* INTERFACE */
346347
347348
/*
348349
** Enable or disable database write protections.
@@ -410,11 +411,14 @@
410411
void db_protect_only(unsigned flags){
411412
if( db.nProtect>=count(db.aProtect)-2 ){
412413
fossil_panic("too many db_protect() calls");
413414
}
414415
db.aProtect[db.nProtect++] = db.protectMask;
415
- if( (flags & PROTECT_SENSITIVE)!=0 && db.bProtectTriggers==0 ){
416
+ if( (flags & PROTECT_SENSITIVE)!=0
417
+ && db.bProtectTriggers==0
418
+ && g.repositoryOpen
419
+ ){
416420
/* Create the triggers needed to protect sensitive settings from
417421
** being created or modified the first time that PROTECT_SENSITIVE
418422
** is enabled. Deleting a sensitive setting is harmless, so there
419423
** is not trigger to block deletes. After being created once, the
420424
** triggers persist for the life of the database connection. */
@@ -453,12 +457,26 @@
453457
** Verify that the desired database write pertections are in place.
454458
** Throw a fatal error if not.
455459
*/
456460
void db_assert_protected(unsigned flags){
457461
if( (flags & db.protectMask)!=flags ){
458
- fossil_fatal("internal security assertion fault: missing "
459
- "database protection bits: %02x", flags & ~db.protectMask);
462
+ fossil_panic("missing database write protection bits: %02x",
463
+ flags & ~db.protectMask);
464
+ }
465
+}
466
+
467
+/*
468
+** Assert that either all protections are off (including PROTECT_BASELINE
469
+** which is usually always enabled), or the setting named in the argument
470
+** is no a sensitive setting.
471
+**
472
+** This assert() is used to verify that the db_set() and db_set_int()
473
+** interfaces do not modify a sensitive setting.
474
+*/
475
+void db_assert_protection_off_or_not_sensitive(const char *zName){
476
+ if( db.protectMask!=0 && db_setting_is_protected(zName) ){
477
+ fossil_panic("unauthorized change to protected setting \"%s\"", zName);
460478
}
461479
}
462480
463481
/*
464482
** Every Fossil database connection automatically registers the following
@@ -1295,34 +1313,36 @@
12951313
}
12961314
strcpy(zOut, zTemp = obscure((char*)zIn));
12971315
fossil_free(zTemp);
12981316
sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
12991317
}
1318
+
1319
+/*
1320
+** Return True if zName is a protected (a.k.a. "sensitive") setting.
1321
+*/
1322
+int db_setting_is_protected(const char *zName){
1323
+ const Setting *pSetting = zName ? db_find_setting(zName,0) : 0;
1324
+ return pSetting!=0 && pSetting->sensitive!=0;
1325
+}
13001326
13011327
/*
13021328
** Implement the protected_setting(X) SQL function. This function returns
13031329
** true if X is the name of a protected (security-sensitive) setting and
13041330
** the db.protectSensitive flag is enabled. It returns false otherwise.
13051331
*/
1306
-LOCAL void db_protected_setting(
1332
+LOCAL void db_protected_setting_func(
13071333
sqlite3_context *context,
13081334
int argc,
13091335
sqlite3_value **argv
13101336
){
13111337
const char *zSetting;
1312
- const Setting *pSetting;
13131338
if( (db.protectMask & PROTECT_SENSITIVE)==0 ){
13141339
sqlite3_result_int(context, 0);
13151340
return;
13161341
}
13171342
zSetting = (const char*)sqlite3_value_text(argv[0]);
1318
- pSetting = zSetting ? db_find_setting(zSetting,0) : 0;
1319
- if( pSetting && pSetting->sensitive ){
1320
- sqlite3_result_int(context, 1);
1321
- }else{
1322
- sqlite3_result_int(context, 0);
1323
- }
1343
+ sqlite3_result_int(context, db_setting_is_protected(zSetting));
13241344
}
13251345
13261346
/*
13271347
** Register the SQL functions that are useful both to the internal
13281348
** representation and to the "fossil sql" command.
@@ -1351,11 +1371,11 @@
13511371
sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0,
13521372
alert_display_name_func, 0, 0);
13531373
sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0,
13541374
db_obscure, 0, 0);
13551375
sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
1356
- db_protected_setting, 0, 0);
1376
+ db_protected_setting_func, 0, 0);
13571377
}
13581378
13591379
#if USE_SEE
13601380
/*
13611381
** This is a pointer to the saved database encryption key string.
@@ -3103,12 +3123,13 @@
31033123
z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
31043124
}
31053125
return z;
31063126
}
31073127
void db_set(const char *zName, const char *zValue, int globalFlag){
3108
- db_begin_transaction();
3128
+ db_assert_protection_off_or_not_sensitive(zName);
31093129
db_unprotect(PROTECT_CONFIG);
3130
+ db_begin_transaction();
31103131
if( globalFlag ){
31113132
db_swap_connections();
31123133
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
31133134
zName, zValue);
31143135
db_swap_connections();
@@ -3117,12 +3138,12 @@
31173138
zName, zValue);
31183139
}
31193140
if( globalFlag && g.repositoryOpen ){
31203141
db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
31213142
}
3122
- db_protect_pop();
31233143
db_end_transaction(0);
3144
+ db_protect_pop();
31243145
}
31253146
void db_unset(const char *zName, int globalFlag){
31263147
db_begin_transaction();
31273148
db_unprotect(PROTECT_CONFIG);
31283149
if( globalFlag ){
@@ -3167,10 +3188,11 @@
31673188
db_swap_connections();
31683189
}
31693190
return v;
31703191
}
31713192
void db_set_int(const char *zName, int value, int globalFlag){
3193
+ db_assert_protection_off_or_not_sensitive(zName);
31723194
db_unprotect(PROTECT_CONFIG);
31733195
if( globalFlag ){
31743196
db_swap_connections();
31753197
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)",
31763198
zName, value);
@@ -4301,11 +4323,13 @@
43014323
fossil_fatal("cannot set 'manifest' globally");
43024324
}
43034325
if( unsetFlag ){
43044326
db_unset(pSetting->name, globalFlag);
43054327
}else{
4328
+ db_protect_only(PROTECT_NONE);
43064329
db_set(pSetting->name, g.argv[3], globalFlag);
4330
+ db_protect_pop();
43074331
}
43084332
if( isManifest && g.localOpen ){
43094333
manifest_to_disk(db_lget_int("checkout", 0));
43104334
}
43114335
}else{
43124336
--- src/db.c
+++ src/db.c
@@ -139,11 +139,11 @@
139 const char *zAuthName; /* Name of the authorizer */
140 int bProtectTriggers; /* True if protection triggers already exist */
141 int nProtect; /* Slots of aProtect used */
142 unsigned aProtect[10]; /* Saved values of protectMask */
143 } db = {
144 PROTECT_USER|PROTECT_CONFIG, /* protectMask */
145 0, 0, 0, 0, 0, 0, };
146
147 /*
148 ** Arrange for the given file to be deleted on a failure.
149 */
@@ -338,11 +338,12 @@
338 */
339 #define PROTECT_USER 0x01 /* USER table */
340 #define PROTECT_CONFIG 0x02 /* CONFIG and GLOBAL_CONFIG tables */
341 #define PROTECT_SENSITIVE 0x04 /* Sensitive and/or global settings */
342 #define PROTECT_READONLY 0x08 /* everything except TEMP tables */
343 #define PROTECT_ALL 0x0f /* All of the above */
 
344 #define PROTECT_NONE 0x00 /* Nothing. Everything is open */
345 #endif /* INTERFACE */
346
347 /*
348 ** Enable or disable database write protections.
@@ -410,11 +411,14 @@
410 void db_protect_only(unsigned flags){
411 if( db.nProtect>=count(db.aProtect)-2 ){
412 fossil_panic("too many db_protect() calls");
413 }
414 db.aProtect[db.nProtect++] = db.protectMask;
415 if( (flags & PROTECT_SENSITIVE)!=0 && db.bProtectTriggers==0 ){
 
 
 
416 /* Create the triggers needed to protect sensitive settings from
417 ** being created or modified the first time that PROTECT_SENSITIVE
418 ** is enabled. Deleting a sensitive setting is harmless, so there
419 ** is not trigger to block deletes. After being created once, the
420 ** triggers persist for the life of the database connection. */
@@ -453,12 +457,26 @@
453 ** Verify that the desired database write pertections are in place.
454 ** Throw a fatal error if not.
455 */
456 void db_assert_protected(unsigned flags){
457 if( (flags & db.protectMask)!=flags ){
458 fossil_fatal("internal security assertion fault: missing "
459 "database protection bits: %02x", flags & ~db.protectMask);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460 }
461 }
462
463 /*
464 ** Every Fossil database connection automatically registers the following
@@ -1295,34 +1313,36 @@
1295 }
1296 strcpy(zOut, zTemp = obscure((char*)zIn));
1297 fossil_free(zTemp);
1298 sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
1299 }
 
 
 
 
 
 
 
 
1300
1301 /*
1302 ** Implement the protected_setting(X) SQL function. This function returns
1303 ** true if X is the name of a protected (security-sensitive) setting and
1304 ** the db.protectSensitive flag is enabled. It returns false otherwise.
1305 */
1306 LOCAL void db_protected_setting(
1307 sqlite3_context *context,
1308 int argc,
1309 sqlite3_value **argv
1310 ){
1311 const char *zSetting;
1312 const Setting *pSetting;
1313 if( (db.protectMask & PROTECT_SENSITIVE)==0 ){
1314 sqlite3_result_int(context, 0);
1315 return;
1316 }
1317 zSetting = (const char*)sqlite3_value_text(argv[0]);
1318 pSetting = zSetting ? db_find_setting(zSetting,0) : 0;
1319 if( pSetting && pSetting->sensitive ){
1320 sqlite3_result_int(context, 1);
1321 }else{
1322 sqlite3_result_int(context, 0);
1323 }
1324 }
1325
1326 /*
1327 ** Register the SQL functions that are useful both to the internal
1328 ** representation and to the "fossil sql" command.
@@ -1351,11 +1371,11 @@
1351 sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0,
1352 alert_display_name_func, 0, 0);
1353 sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0,
1354 db_obscure, 0, 0);
1355 sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
1356 db_protected_setting, 0, 0);
1357 }
1358
1359 #if USE_SEE
1360 /*
1361 ** This is a pointer to the saved database encryption key string.
@@ -3103,12 +3123,13 @@
3103 z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
3104 }
3105 return z;
3106 }
3107 void db_set(const char *zName, const char *zValue, int globalFlag){
3108 db_begin_transaction();
3109 db_unprotect(PROTECT_CONFIG);
 
3110 if( globalFlag ){
3111 db_swap_connections();
3112 db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
3113 zName, zValue);
3114 db_swap_connections();
@@ -3117,12 +3138,12 @@
3117 zName, zValue);
3118 }
3119 if( globalFlag && g.repositoryOpen ){
3120 db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
3121 }
3122 db_protect_pop();
3123 db_end_transaction(0);
 
3124 }
3125 void db_unset(const char *zName, int globalFlag){
3126 db_begin_transaction();
3127 db_unprotect(PROTECT_CONFIG);
3128 if( globalFlag ){
@@ -3167,10 +3188,11 @@
3167 db_swap_connections();
3168 }
3169 return v;
3170 }
3171 void db_set_int(const char *zName, int value, int globalFlag){
 
3172 db_unprotect(PROTECT_CONFIG);
3173 if( globalFlag ){
3174 db_swap_connections();
3175 db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)",
3176 zName, value);
@@ -4301,11 +4323,13 @@
4301 fossil_fatal("cannot set 'manifest' globally");
4302 }
4303 if( unsetFlag ){
4304 db_unset(pSetting->name, globalFlag);
4305 }else{
 
4306 db_set(pSetting->name, g.argv[3], globalFlag);
 
4307 }
4308 if( isManifest && g.localOpen ){
4309 manifest_to_disk(db_lget_int("checkout", 0));
4310 }
4311 }else{
4312
--- src/db.c
+++ src/db.c
@@ -139,11 +139,11 @@
139 const char *zAuthName; /* Name of the authorizer */
140 int bProtectTriggers; /* True if protection triggers already exist */
141 int nProtect; /* Slots of aProtect used */
142 unsigned aProtect[10]; /* Saved values of protectMask */
143 } db = {
144 PROTECT_USER|PROTECT_CONFIG|PROTECT_BASELINE, /* protectMask */
145 0, 0, 0, 0, 0, 0, };
146
147 /*
148 ** Arrange for the given file to be deleted on a failure.
149 */
@@ -338,11 +338,12 @@
338 */
339 #define PROTECT_USER 0x01 /* USER table */
340 #define PROTECT_CONFIG 0x02 /* CONFIG and GLOBAL_CONFIG tables */
341 #define PROTECT_SENSITIVE 0x04 /* Sensitive and/or global settings */
342 #define PROTECT_READONLY 0x08 /* everything except TEMP tables */
343 #define PROTECT_BASELINE 0x10 /* protection system is working */
344 #define PROTECT_ALL 0x1f /* All of the above */
345 #define PROTECT_NONE 0x00 /* Nothing. Everything is open */
346 #endif /* INTERFACE */
347
348 /*
349 ** Enable or disable database write protections.
@@ -410,11 +411,14 @@
411 void db_protect_only(unsigned flags){
412 if( db.nProtect>=count(db.aProtect)-2 ){
413 fossil_panic("too many db_protect() calls");
414 }
415 db.aProtect[db.nProtect++] = db.protectMask;
416 if( (flags & PROTECT_SENSITIVE)!=0
417 && db.bProtectTriggers==0
418 && g.repositoryOpen
419 ){
420 /* Create the triggers needed to protect sensitive settings from
421 ** being created or modified the first time that PROTECT_SENSITIVE
422 ** is enabled. Deleting a sensitive setting is harmless, so there
423 ** is not trigger to block deletes. After being created once, the
424 ** triggers persist for the life of the database connection. */
@@ -453,12 +457,26 @@
457 ** Verify that the desired database write pertections are in place.
458 ** Throw a fatal error if not.
459 */
460 void db_assert_protected(unsigned flags){
461 if( (flags & db.protectMask)!=flags ){
462 fossil_panic("missing database write protection bits: %02x",
463 flags & ~db.protectMask);
464 }
465 }
466
467 /*
468 ** Assert that either all protections are off (including PROTECT_BASELINE
469 ** which is usually always enabled), or the setting named in the argument
470 ** is no a sensitive setting.
471 **
472 ** This assert() is used to verify that the db_set() and db_set_int()
473 ** interfaces do not modify a sensitive setting.
474 */
475 void db_assert_protection_off_or_not_sensitive(const char *zName){
476 if( db.protectMask!=0 && db_setting_is_protected(zName) ){
477 fossil_panic("unauthorized change to protected setting \"%s\"", zName);
478 }
479 }
480
481 /*
482 ** Every Fossil database connection automatically registers the following
@@ -1295,34 +1313,36 @@
1313 }
1314 strcpy(zOut, zTemp = obscure((char*)zIn));
1315 fossil_free(zTemp);
1316 sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
1317 }
1318
1319 /*
1320 ** Return True if zName is a protected (a.k.a. "sensitive") setting.
1321 */
1322 int db_setting_is_protected(const char *zName){
1323 const Setting *pSetting = zName ? db_find_setting(zName,0) : 0;
1324 return pSetting!=0 && pSetting->sensitive!=0;
1325 }
1326
1327 /*
1328 ** Implement the protected_setting(X) SQL function. This function returns
1329 ** true if X is the name of a protected (security-sensitive) setting and
1330 ** the db.protectSensitive flag is enabled. It returns false otherwise.
1331 */
1332 LOCAL void db_protected_setting_func(
1333 sqlite3_context *context,
1334 int argc,
1335 sqlite3_value **argv
1336 ){
1337 const char *zSetting;
 
1338 if( (db.protectMask & PROTECT_SENSITIVE)==0 ){
1339 sqlite3_result_int(context, 0);
1340 return;
1341 }
1342 zSetting = (const char*)sqlite3_value_text(argv[0]);
1343 sqlite3_result_int(context, db_setting_is_protected(zSetting));
 
 
 
 
 
1344 }
1345
1346 /*
1347 ** Register the SQL functions that are useful both to the internal
1348 ** representation and to the "fossil sql" command.
@@ -1351,11 +1371,11 @@
1371 sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0,
1372 alert_display_name_func, 0, 0);
1373 sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0,
1374 db_obscure, 0, 0);
1375 sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
1376 db_protected_setting_func, 0, 0);
1377 }
1378
1379 #if USE_SEE
1380 /*
1381 ** This is a pointer to the saved database encryption key string.
@@ -3103,12 +3123,13 @@
3123 z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
3124 }
3125 return z;
3126 }
3127 void db_set(const char *zName, const char *zValue, int globalFlag){
3128 db_assert_protection_off_or_not_sensitive(zName);
3129 db_unprotect(PROTECT_CONFIG);
3130 db_begin_transaction();
3131 if( globalFlag ){
3132 db_swap_connections();
3133 db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
3134 zName, zValue);
3135 db_swap_connections();
@@ -3117,12 +3138,12 @@
3138 zName, zValue);
3139 }
3140 if( globalFlag && g.repositoryOpen ){
3141 db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
3142 }
 
3143 db_end_transaction(0);
3144 db_protect_pop();
3145 }
3146 void db_unset(const char *zName, int globalFlag){
3147 db_begin_transaction();
3148 db_unprotect(PROTECT_CONFIG);
3149 if( globalFlag ){
@@ -3167,10 +3188,11 @@
3188 db_swap_connections();
3189 }
3190 return v;
3191 }
3192 void db_set_int(const char *zName, int value, int globalFlag){
3193 db_assert_protection_off_or_not_sensitive(zName);
3194 db_unprotect(PROTECT_CONFIG);
3195 if( globalFlag ){
3196 db_swap_connections();
3197 db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)",
3198 zName, value);
@@ -4301,11 +4323,13 @@
4323 fossil_fatal("cannot set 'manifest' globally");
4324 }
4325 if( unsetFlag ){
4326 db_unset(pSetting->name, globalFlag);
4327 }else{
4328 db_protect_only(PROTECT_NONE);
4329 db_set(pSetting->name, g.argv[3], globalFlag);
4330 db_protect_pop();
4331 }
4332 if( isManifest && g.localOpen ){
4333 manifest_to_disk(db_lget_int("checkout", 0));
4334 }
4335 }else{
4336
--- src/setup.c
+++ src/setup.c
@@ -197,11 +197,13 @@
197197
}
198198
if( zQ ){
199199
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
200200
if( iQ!=iVal ){
201201
login_verify_csrf_secret();
202
+ db_protect_only(PROTECT_NONE);
202203
db_set(zVar, iQ ? "1" : "0", 0);
204
+ db_protect_pop();
203205
setup_incr_cfgcnt();
204206
admin_log("Set option [%q] to [%q].",
205207
zVar, iQ ? "on" : "off");
206208
iVal = iQ;
207209
}
@@ -232,11 +234,13 @@
232234
const char *zQ = P(zQParm);
233235
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
234236
const int nZQ = (int)strlen(zQ);
235237
login_verify_csrf_secret();
236238
setup_incr_cfgcnt();
239
+ db_protect_only(PROTECT_NONE);
237240
db_set(zVar, zQ, 0);
241
+ db_protect_pop();
238242
admin_log("Set entry_attribute %Q to: %.*s%s",
239243
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
240244
zVal = zQ;
241245
}
242246
@ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
@@ -262,11 +266,13 @@
262266
const char *z = db_get(zVar, zDflt);
263267
const char *zQ = P(zQP);
264268
if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
265269
const int nZQ = (int)strlen(zQ);
266270
login_verify_csrf_secret();
271
+ db_protect_only(PROTECT_NONE);
267272
db_set(zVar, zQ, 0);
273
+ db_protect_pop();
268274
setup_incr_cfgcnt();
269275
admin_log("Set textarea_attribute %Q to: %.*s%s",
270276
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
271277
z = zQ;
272278
}
273279
--- src/setup.c
+++ src/setup.c
@@ -197,11 +197,13 @@
197 }
198 if( zQ ){
199 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
200 if( iQ!=iVal ){
201 login_verify_csrf_secret();
 
202 db_set(zVar, iQ ? "1" : "0", 0);
 
203 setup_incr_cfgcnt();
204 admin_log("Set option [%q] to [%q].",
205 zVar, iQ ? "on" : "off");
206 iVal = iQ;
207 }
@@ -232,11 +234,13 @@
232 const char *zQ = P(zQParm);
233 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
234 const int nZQ = (int)strlen(zQ);
235 login_verify_csrf_secret();
236 setup_incr_cfgcnt();
 
237 db_set(zVar, zQ, 0);
 
238 admin_log("Set entry_attribute %Q to: %.*s%s",
239 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
240 zVal = zQ;
241 }
242 @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
@@ -262,11 +266,13 @@
262 const char *z = db_get(zVar, zDflt);
263 const char *zQ = P(zQP);
264 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
265 const int nZQ = (int)strlen(zQ);
266 login_verify_csrf_secret();
 
267 db_set(zVar, zQ, 0);
 
268 setup_incr_cfgcnt();
269 admin_log("Set textarea_attribute %Q to: %.*s%s",
270 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
271 z = zQ;
272 }
273
--- src/setup.c
+++ src/setup.c
@@ -197,11 +197,13 @@
197 }
198 if( zQ ){
199 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
200 if( iQ!=iVal ){
201 login_verify_csrf_secret();
202 db_protect_only(PROTECT_NONE);
203 db_set(zVar, iQ ? "1" : "0", 0);
204 db_protect_pop();
205 setup_incr_cfgcnt();
206 admin_log("Set option [%q] to [%q].",
207 zVar, iQ ? "on" : "off");
208 iVal = iQ;
209 }
@@ -232,11 +234,13 @@
234 const char *zQ = P(zQParm);
235 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
236 const int nZQ = (int)strlen(zQ);
237 login_verify_csrf_secret();
238 setup_incr_cfgcnt();
239 db_protect_only(PROTECT_NONE);
240 db_set(zVar, zQ, 0);
241 db_protect_pop();
242 admin_log("Set entry_attribute %Q to: %.*s%s",
243 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
244 zVal = zQ;
245 }
246 @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
@@ -262,11 +266,13 @@
266 const char *z = db_get(zVar, zDflt);
267 const char *zQ = P(zQP);
268 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
269 const int nZQ = (int)strlen(zQ);
270 login_verify_csrf_secret();
271 db_protect_only(PROTECT_NONE);
272 db_set(zVar, zQ, 0);
273 db_protect_pop();
274 setup_incr_cfgcnt();
275 admin_log("Set textarea_attribute %Q to: %.*s%s",
276 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
277 z = zQ;
278 }
279

Keyboard Shortcuts

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