Fossil SCM
Additional checks to ensure that db_set() and db_set_int() do not modify a sensitive setting unless PROTECT_BASELINE is disabled.
Commit
ccdb5a9bb8b7a188e8c466a800ab9f9dff69bb5c10a8e6b5ddbd23b11143ddd9
Parent
c75dcc621bb0fee…
2 files changed
+40
-16
+6
M
src/db.c
+40
-16
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -139,11 +139,11 @@ | ||
| 139 | 139 | const char *zAuthName; /* Name of the authorizer */ |
| 140 | 140 | int bProtectTriggers; /* True if protection triggers already exist */ |
| 141 | 141 | int nProtect; /* Slots of aProtect used */ |
| 142 | 142 | unsigned aProtect[10]; /* Saved values of protectMask */ |
| 143 | 143 | } db = { |
| 144 | - PROTECT_USER|PROTECT_CONFIG, /* protectMask */ | |
| 144 | + PROTECT_USER|PROTECT_CONFIG|PROTECT_BASELINE, /* protectMask */ | |
| 145 | 145 | 0, 0, 0, 0, 0, 0, }; |
| 146 | 146 | |
| 147 | 147 | /* |
| 148 | 148 | ** Arrange for the given file to be deleted on a failure. |
| 149 | 149 | */ |
| @@ -338,11 +338,12 @@ | ||
| 338 | 338 | */ |
| 339 | 339 | #define PROTECT_USER 0x01 /* USER table */ |
| 340 | 340 | #define PROTECT_CONFIG 0x02 /* CONFIG and GLOBAL_CONFIG tables */ |
| 341 | 341 | #define PROTECT_SENSITIVE 0x04 /* Sensitive and/or global settings */ |
| 342 | 342 | #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 */ | |
| 344 | 345 | #define PROTECT_NONE 0x00 /* Nothing. Everything is open */ |
| 345 | 346 | #endif /* INTERFACE */ |
| 346 | 347 | |
| 347 | 348 | /* |
| 348 | 349 | ** Enable or disable database write protections. |
| @@ -410,11 +411,14 @@ | ||
| 410 | 411 | void db_protect_only(unsigned flags){ |
| 411 | 412 | if( db.nProtect>=count(db.aProtect)-2 ){ |
| 412 | 413 | fossil_panic("too many db_protect() calls"); |
| 413 | 414 | } |
| 414 | 415 | 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 | + ){ | |
| 416 | 420 | /* Create the triggers needed to protect sensitive settings from |
| 417 | 421 | ** being created or modified the first time that PROTECT_SENSITIVE |
| 418 | 422 | ** is enabled. Deleting a sensitive setting is harmless, so there |
| 419 | 423 | ** is not trigger to block deletes. After being created once, the |
| 420 | 424 | ** triggers persist for the life of the database connection. */ |
| @@ -453,12 +457,26 @@ | ||
| 453 | 457 | ** Verify that the desired database write pertections are in place. |
| 454 | 458 | ** Throw a fatal error if not. |
| 455 | 459 | */ |
| 456 | 460 | void db_assert_protected(unsigned flags){ |
| 457 | 461 | 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); | |
| 460 | 478 | } |
| 461 | 479 | } |
| 462 | 480 | |
| 463 | 481 | /* |
| 464 | 482 | ** Every Fossil database connection automatically registers the following |
| @@ -1295,34 +1313,36 @@ | ||
| 1295 | 1313 | } |
| 1296 | 1314 | strcpy(zOut, zTemp = obscure((char*)zIn)); |
| 1297 | 1315 | fossil_free(zTemp); |
| 1298 | 1316 | sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free); |
| 1299 | 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 | +} | |
| 1300 | 1326 | |
| 1301 | 1327 | /* |
| 1302 | 1328 | ** Implement the protected_setting(X) SQL function. This function returns |
| 1303 | 1329 | ** true if X is the name of a protected (security-sensitive) setting and |
| 1304 | 1330 | ** the db.protectSensitive flag is enabled. It returns false otherwise. |
| 1305 | 1331 | */ |
| 1306 | -LOCAL void db_protected_setting( | |
| 1332 | +LOCAL void db_protected_setting_func( | |
| 1307 | 1333 | sqlite3_context *context, |
| 1308 | 1334 | int argc, |
| 1309 | 1335 | sqlite3_value **argv |
| 1310 | 1336 | ){ |
| 1311 | 1337 | const char *zSetting; |
| 1312 | - const Setting *pSetting; | |
| 1313 | 1338 | if( (db.protectMask & PROTECT_SENSITIVE)==0 ){ |
| 1314 | 1339 | sqlite3_result_int(context, 0); |
| 1315 | 1340 | return; |
| 1316 | 1341 | } |
| 1317 | 1342 | 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)); | |
| 1324 | 1344 | } |
| 1325 | 1345 | |
| 1326 | 1346 | /* |
| 1327 | 1347 | ** Register the SQL functions that are useful both to the internal |
| 1328 | 1348 | ** representation and to the "fossil sql" command. |
| @@ -1351,11 +1371,11 @@ | ||
| 1351 | 1371 | sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0, |
| 1352 | 1372 | alert_display_name_func, 0, 0); |
| 1353 | 1373 | sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0, |
| 1354 | 1374 | db_obscure, 0, 0); |
| 1355 | 1375 | sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0, |
| 1356 | - db_protected_setting, 0, 0); | |
| 1376 | + db_protected_setting_func, 0, 0); | |
| 1357 | 1377 | } |
| 1358 | 1378 | |
| 1359 | 1379 | #if USE_SEE |
| 1360 | 1380 | /* |
| 1361 | 1381 | ** This is a pointer to the saved database encryption key string. |
| @@ -3103,12 +3123,13 @@ | ||
| 3103 | 3123 | z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z); |
| 3104 | 3124 | } |
| 3105 | 3125 | return z; |
| 3106 | 3126 | } |
| 3107 | 3127 | void db_set(const char *zName, const char *zValue, int globalFlag){ |
| 3108 | - db_begin_transaction(); | |
| 3128 | + db_assert_protection_off_or_not_sensitive(zName); | |
| 3109 | 3129 | db_unprotect(PROTECT_CONFIG); |
| 3130 | + db_begin_transaction(); | |
| 3110 | 3131 | if( globalFlag ){ |
| 3111 | 3132 | db_swap_connections(); |
| 3112 | 3133 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", |
| 3113 | 3134 | zName, zValue); |
| 3114 | 3135 | db_swap_connections(); |
| @@ -3117,12 +3138,12 @@ | ||
| 3117 | 3138 | zName, zValue); |
| 3118 | 3139 | } |
| 3119 | 3140 | if( globalFlag && g.repositoryOpen ){ |
| 3120 | 3141 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 3121 | 3142 | } |
| 3122 | - db_protect_pop(); | |
| 3123 | 3143 | db_end_transaction(0); |
| 3144 | + db_protect_pop(); | |
| 3124 | 3145 | } |
| 3125 | 3146 | void db_unset(const char *zName, int globalFlag){ |
| 3126 | 3147 | db_begin_transaction(); |
| 3127 | 3148 | db_unprotect(PROTECT_CONFIG); |
| 3128 | 3149 | if( globalFlag ){ |
| @@ -3167,10 +3188,11 @@ | ||
| 3167 | 3188 | db_swap_connections(); |
| 3168 | 3189 | } |
| 3169 | 3190 | return v; |
| 3170 | 3191 | } |
| 3171 | 3192 | void db_set_int(const char *zName, int value, int globalFlag){ |
| 3193 | + db_assert_protection_off_or_not_sensitive(zName); | |
| 3172 | 3194 | db_unprotect(PROTECT_CONFIG); |
| 3173 | 3195 | if( globalFlag ){ |
| 3174 | 3196 | db_swap_connections(); |
| 3175 | 3197 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", |
| 3176 | 3198 | zName, value); |
| @@ -4301,11 +4323,13 @@ | ||
| 4301 | 4323 | fossil_fatal("cannot set 'manifest' globally"); |
| 4302 | 4324 | } |
| 4303 | 4325 | if( unsetFlag ){ |
| 4304 | 4326 | db_unset(pSetting->name, globalFlag); |
| 4305 | 4327 | }else{ |
| 4328 | + db_protect_only(PROTECT_NONE); | |
| 4306 | 4329 | db_set(pSetting->name, g.argv[3], globalFlag); |
| 4330 | + db_protect_pop(); | |
| 4307 | 4331 | } |
| 4308 | 4332 | if( isManifest && g.localOpen ){ |
| 4309 | 4333 | manifest_to_disk(db_lget_int("checkout", 0)); |
| 4310 | 4334 | } |
| 4311 | 4335 | }else{ |
| 4312 | 4336 |
| --- 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 |
+6
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -197,11 +197,13 @@ | ||
| 197 | 197 | } |
| 198 | 198 | if( zQ ){ |
| 199 | 199 | int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); |
| 200 | 200 | if( iQ!=iVal ){ |
| 201 | 201 | login_verify_csrf_secret(); |
| 202 | + db_protect_only(PROTECT_NONE); | |
| 202 | 203 | db_set(zVar, iQ ? "1" : "0", 0); |
| 204 | + db_protect_pop(); | |
| 203 | 205 | setup_incr_cfgcnt(); |
| 204 | 206 | admin_log("Set option [%q] to [%q].", |
| 205 | 207 | zVar, iQ ? "on" : "off"); |
| 206 | 208 | iVal = iQ; |
| 207 | 209 | } |
| @@ -232,11 +234,13 @@ | ||
| 232 | 234 | const char *zQ = P(zQParm); |
| 233 | 235 | if( zQ && fossil_strcmp(zQ,zVal)!=0 ){ |
| 234 | 236 | const int nZQ = (int)strlen(zQ); |
| 235 | 237 | login_verify_csrf_secret(); |
| 236 | 238 | setup_incr_cfgcnt(); |
| 239 | + db_protect_only(PROTECT_NONE); | |
| 237 | 240 | db_set(zVar, zQ, 0); |
| 241 | + db_protect_pop(); | |
| 238 | 242 | admin_log("Set entry_attribute %Q to: %.*s%s", |
| 239 | 243 | zVar, 20, zQ, (nZQ>20 ? "..." : "")); |
| 240 | 244 | zVal = zQ; |
| 241 | 245 | } |
| 242 | 246 | @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \ |
| @@ -262,11 +266,13 @@ | ||
| 262 | 266 | const char *z = db_get(zVar, zDflt); |
| 263 | 267 | const char *zQ = P(zQP); |
| 264 | 268 | if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){ |
| 265 | 269 | const int nZQ = (int)strlen(zQ); |
| 266 | 270 | login_verify_csrf_secret(); |
| 271 | + db_protect_only(PROTECT_NONE); | |
| 267 | 272 | db_set(zVar, zQ, 0); |
| 273 | + db_protect_pop(); | |
| 268 | 274 | setup_incr_cfgcnt(); |
| 269 | 275 | admin_log("Set textarea_attribute %Q to: %.*s%s", |
| 270 | 276 | zVar, 20, zQ, (nZQ>20 ? "..." : "")); |
| 271 | 277 | z = zQ; |
| 272 | 278 | } |
| 273 | 279 |
| --- 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 |