Fossil SCM

Allow DROP INDEX and DROP VIEW through the ticket-schema authorizer. Enhance the test-db-prepare command so that it can use the ticket-schema or report authorizers for testing purposes.

drh 2021-06-14 19:51 trunk merge
Commit c717f1ef9a1a4c91d1f3ea589ee4e5fb358a41f2a151297420c8d0eea85faa19
3 files changed +34 -1 +5 -1 +23 -2
+34 -1
--- src/db.c
+++ src/db.c
@@ -864,23 +864,56 @@
864864
db_exec(&err);
865865
}
866866
867867
/*
868868
** COMMAND: test-db-prepare
869
-** Usage: %fossil test-db-prepare ?OPTIONS? SQL
869
+** Usage: %fossil test-db-prepare ?OPTIONS? SQL-STATEMENT
870
+**
871
+** Options:
872
+**
873
+** --auth-report Enable the ticket report query authorizer.
874
+** --auth-ticket Enable the ticket schema query authorizer.
870875
**
871876
** Invoke db_prepare() on the SQL input. Report any errors encountered.
872877
** This command is used to verify error detection logic in the db_prepare()
873878
** utility routine.
874879
*/
875880
void db_test_db_prepare(void){
881
+ const int fAuthReport = find_option("auth-report",0,0)!=0;
882
+ const int fAuthSchema = find_option("auth-ticket",0,0)!=0;
883
+ const int fAuth = fAuthReport + fAuthSchema;
884
+ char * zReportErr = 0; /* auth-report error string. */
885
+ int nSchemaErr = 0; /* Number of auth-ticket errors. */
876886
Stmt err;
887
+
888
+ if(fAuth>1){
889
+ fossil_fatal("Only one of --auth-report or --auth-ticket "
890
+ "may be used.");
891
+ }
877892
db_find_and_open_repository(0,0);
878893
verify_all_options();
879894
if( g.argc!=3 ) usage("?OPTIONS? SQL");
895
+ if(fAuthReport){
896
+ report_restrict_sql(&zReportErr);
897
+ }else if(fAuthSchema){
898
+ ticket_restrict_sql(&nSchemaErr);
899
+ }
880900
db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
881901
db_finalize(&err);
902
+ if(fAuthReport){
903
+ report_unrestrict_sql();
904
+ if(zReportErr){
905
+ fossil_warning("Report authorizer error: %s\n", zReportErr);
906
+ fossil_free(zReportErr);
907
+ }
908
+ }else if(fAuthSchema){
909
+ ticket_unrestrict_sql();
910
+ if(nSchemaErr){
911
+ fossil_warning("Ticket schema authorizer error count: %d\n",
912
+ nSchemaErr);
913
+ }
914
+ }
882915
}
883916
884917
/*
885918
** Print the output of one or more SQL queries on standard output.
886919
** This routine is used for debugging purposes only.
887920
--- src/db.c
+++ src/db.c
@@ -864,23 +864,56 @@
864 db_exec(&err);
865 }
866
867 /*
868 ** COMMAND: test-db-prepare
869 ** Usage: %fossil test-db-prepare ?OPTIONS? SQL
 
 
 
 
 
870 **
871 ** Invoke db_prepare() on the SQL input. Report any errors encountered.
872 ** This command is used to verify error detection logic in the db_prepare()
873 ** utility routine.
874 */
875 void db_test_db_prepare(void){
 
 
 
 
 
876 Stmt err;
 
 
 
 
 
877 db_find_and_open_repository(0,0);
878 verify_all_options();
879 if( g.argc!=3 ) usage("?OPTIONS? SQL");
 
 
 
 
 
880 db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
881 db_finalize(&err);
 
 
 
 
 
 
 
 
 
 
 
 
 
882 }
883
884 /*
885 ** Print the output of one or more SQL queries on standard output.
886 ** This routine is used for debugging purposes only.
887
--- src/db.c
+++ src/db.c
@@ -864,23 +864,56 @@
864 db_exec(&err);
865 }
866
867 /*
868 ** COMMAND: test-db-prepare
869 ** Usage: %fossil test-db-prepare ?OPTIONS? SQL-STATEMENT
870 **
871 ** Options:
872 **
873 ** --auth-report Enable the ticket report query authorizer.
874 ** --auth-ticket Enable the ticket schema query authorizer.
875 **
876 ** Invoke db_prepare() on the SQL input. Report any errors encountered.
877 ** This command is used to verify error detection logic in the db_prepare()
878 ** utility routine.
879 */
880 void db_test_db_prepare(void){
881 const int fAuthReport = find_option("auth-report",0,0)!=0;
882 const int fAuthSchema = find_option("auth-ticket",0,0)!=0;
883 const int fAuth = fAuthReport + fAuthSchema;
884 char * zReportErr = 0; /* auth-report error string. */
885 int nSchemaErr = 0; /* Number of auth-ticket errors. */
886 Stmt err;
887
888 if(fAuth>1){
889 fossil_fatal("Only one of --auth-report or --auth-ticket "
890 "may be used.");
891 }
892 db_find_and_open_repository(0,0);
893 verify_all_options();
894 if( g.argc!=3 ) usage("?OPTIONS? SQL");
895 if(fAuthReport){
896 report_restrict_sql(&zReportErr);
897 }else if(fAuthSchema){
898 ticket_restrict_sql(&nSchemaErr);
899 }
900 db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
901 db_finalize(&err);
902 if(fAuthReport){
903 report_unrestrict_sql();
904 if(zReportErr){
905 fossil_warning("Report authorizer error: %s\n", zReportErr);
906 fossil_free(zReportErr);
907 }
908 }else if(fAuthSchema){
909 ticket_unrestrict_sql();
910 if(nSchemaErr){
911 fossil_warning("Ticket schema authorizer error count: %d\n",
912 nSchemaErr);
913 }
914 }
915 }
916
917 /*
918 ** Print the output of one or more SQL queries on standard output.
919 ** This routine is used for debugging purposes only.
920
+5 -1
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161161
/*
162162
** This is the SQLite authorizer callback used to make sure that the
163163
** SQL statements entered by users do not try to do anything untoward.
164164
** If anything suspicious is tried, set *(char**)pError to an error
165165
** message obtained from malloc.
166
+**
167
+** Use the "fossil test-db-prepare --auth-report SQL" command to perform
168
+** manual testing of this authorizer.
166169
*/
167170
static int report_query_authorizer(
168171
void *pError,
169172
int code,
170173
const char *zArg1,
@@ -240,11 +243,12 @@
240243
}
241244
return rc;
242245
}
243246
244247
/*
245
-** Activate the query authorizer
248
+** Activate the ticket report query authorizer. Must be followed by an
249
+** eventual call to report_unrestrict_sql().
246250
*/
247251
void report_restrict_sql(char **pzErr){
248252
db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
249253
sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
250254
}
251255
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161 /*
162 ** This is the SQLite authorizer callback used to make sure that the
163 ** SQL statements entered by users do not try to do anything untoward.
164 ** If anything suspicious is tried, set *(char**)pError to an error
165 ** message obtained from malloc.
 
 
 
166 */
167 static int report_query_authorizer(
168 void *pError,
169 int code,
170 const char *zArg1,
@@ -240,11 +243,12 @@
240 }
241 return rc;
242 }
243
244 /*
245 ** Activate the query authorizer
 
246 */
247 void report_restrict_sql(char **pzErr){
248 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
249 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
250 }
251
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161 /*
162 ** This is the SQLite authorizer callback used to make sure that the
163 ** SQL statements entered by users do not try to do anything untoward.
164 ** If anything suspicious is tried, set *(char**)pError to an error
165 ** message obtained from malloc.
166 **
167 ** Use the "fossil test-db-prepare --auth-report SQL" command to perform
168 ** manual testing of this authorizer.
169 */
170 static int report_query_authorizer(
171 void *pError,
172 int code,
173 const char *zArg1,
@@ -240,11 +243,12 @@
243 }
244 return rc;
245 }
246
247 /*
248 ** Activate the ticket report query authorizer. Must be followed by an
249 ** eventual call to report_unrestrict_sql().
250 */
251 void report_restrict_sql(char **pzErr){
252 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
253 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
254 }
255
+23 -2
--- src/tkt.c
+++ src/tkt.c
@@ -378,10 +378,12 @@
378378
** schema for the ticketing system. Only allow
379379
**
380380
** CREATE TABLE
381381
** CREATE INDEX
382382
** CREATE VIEW
383
+** DROP INDEX
384
+** DROP VIEW
383385
**
384386
** And for objects in "main" or "repository" whose names
385387
** begin with "ticket" or "fx_". Also allow
386388
**
387389
** INSERT
@@ -393,10 +395,13 @@
393395
**
394396
** Of particular importance for security is that this routine
395397
** disallows data changes on the "config" table, as that could
396398
** allow a malicious server to modify settings in such a way as
397399
** to cause a remote code execution.
400
+**
401
+** Use the "fossil test-db-prepare --auth-ticket SQL" command to perform
402
+** manual testing of this authorizer.
398403
*/
399404
static int ticket_schema_auth(
400405
void *pNErr,
401406
int eCode,
402407
const char *z0,
@@ -403,10 +408,11 @@
403408
const char *z1,
404409
const char *z2,
405410
const char *z3
406411
){
407412
switch( eCode ){
413
+ case SQLITE_DROP_VIEW:
408414
case SQLITE_CREATE_VIEW:
409415
case SQLITE_CREATE_TABLE: {
410416
if( sqlite3_stricmp(z2,"main")!=0
411417
&& sqlite3_stricmp(z2,"repository")!=0
412418
){
@@ -417,10 +423,11 @@
417423
){
418424
goto ticket_schema_error;
419425
}
420426
break;
421427
}
428
+ case SQLITE_DROP_INDEX:
422429
case SQLITE_CREATE_INDEX: {
423430
if( sqlite3_stricmp(z2,"main")!=0
424431
&& sqlite3_stricmp(z2,"repository")!=0
425432
){
426433
goto ticket_schema_error;
@@ -463,10 +470,24 @@
463470
ticket_schema_error:
464471
if( pNErr ) *(int*)pNErr = 1;
465472
return SQLITE_DENY;
466473
}
467474
475
+/*
476
+** Activate the ticket schema authorizer. Must be followed by
477
+** an eventual call to ticket_unrestrict_sql().
478
+*/
479
+void ticket_restrict_sql(int * pNErr){
480
+ db_set_authorizer(ticket_schema_auth,(void*)pNErr,"Ticket-Schema");
481
+}
482
+/*
483
+** Deactivate the ticket schema authorizer.
484
+*/
485
+void ticket_unrestrict_sql(void){
486
+ db_clear_authorizer();
487
+}
488
+
468489
469490
/*
470491
** Recreate the TICKET and TICKETCHNG tables.
471492
*/
472493
void ticket_create_table(int separateConnection){
@@ -475,18 +496,18 @@
475496
db_multi_exec(
476497
"DROP TABLE IF EXISTS ticket;"
477498
"DROP TABLE IF EXISTS ticketchng;"
478499
);
479500
zSql = ticket_table_schema();
480
- db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
501
+ ticket_restrict_sql(0);
481502
if( separateConnection ){
482503
if( db_transaction_nesting_depth() ) db_end_transaction(0);
483504
db_init_database(g.zRepositoryName, zSql, 0);
484505
}else{
485506
db_multi_exec("%s", zSql/*safe-for-%s*/);
486507
}
487
- db_clear_authorizer();
508
+ ticket_unrestrict_sql();
488509
fossil_free(zSql);
489510
}
490511
491512
/*
492513
** Repopulate the TICKET and TICKETCHNG tables from scratch using all
493514
--- src/tkt.c
+++ src/tkt.c
@@ -378,10 +378,12 @@
378 ** schema for the ticketing system. Only allow
379 **
380 ** CREATE TABLE
381 ** CREATE INDEX
382 ** CREATE VIEW
 
 
383 **
384 ** And for objects in "main" or "repository" whose names
385 ** begin with "ticket" or "fx_". Also allow
386 **
387 ** INSERT
@@ -393,10 +395,13 @@
393 **
394 ** Of particular importance for security is that this routine
395 ** disallows data changes on the "config" table, as that could
396 ** allow a malicious server to modify settings in such a way as
397 ** to cause a remote code execution.
 
 
 
398 */
399 static int ticket_schema_auth(
400 void *pNErr,
401 int eCode,
402 const char *z0,
@@ -403,10 +408,11 @@
403 const char *z1,
404 const char *z2,
405 const char *z3
406 ){
407 switch( eCode ){
 
408 case SQLITE_CREATE_VIEW:
409 case SQLITE_CREATE_TABLE: {
410 if( sqlite3_stricmp(z2,"main")!=0
411 && sqlite3_stricmp(z2,"repository")!=0
412 ){
@@ -417,10 +423,11 @@
417 ){
418 goto ticket_schema_error;
419 }
420 break;
421 }
 
422 case SQLITE_CREATE_INDEX: {
423 if( sqlite3_stricmp(z2,"main")!=0
424 && sqlite3_stricmp(z2,"repository")!=0
425 ){
426 goto ticket_schema_error;
@@ -463,10 +470,24 @@
463 ticket_schema_error:
464 if( pNErr ) *(int*)pNErr = 1;
465 return SQLITE_DENY;
466 }
467
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
469 /*
470 ** Recreate the TICKET and TICKETCHNG tables.
471 */
472 void ticket_create_table(int separateConnection){
@@ -475,18 +496,18 @@
475 db_multi_exec(
476 "DROP TABLE IF EXISTS ticket;"
477 "DROP TABLE IF EXISTS ticketchng;"
478 );
479 zSql = ticket_table_schema();
480 db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
481 if( separateConnection ){
482 if( db_transaction_nesting_depth() ) db_end_transaction(0);
483 db_init_database(g.zRepositoryName, zSql, 0);
484 }else{
485 db_multi_exec("%s", zSql/*safe-for-%s*/);
486 }
487 db_clear_authorizer();
488 fossil_free(zSql);
489 }
490
491 /*
492 ** Repopulate the TICKET and TICKETCHNG tables from scratch using all
493
--- src/tkt.c
+++ src/tkt.c
@@ -378,10 +378,12 @@
378 ** schema for the ticketing system. Only allow
379 **
380 ** CREATE TABLE
381 ** CREATE INDEX
382 ** CREATE VIEW
383 ** DROP INDEX
384 ** DROP VIEW
385 **
386 ** And for objects in "main" or "repository" whose names
387 ** begin with "ticket" or "fx_". Also allow
388 **
389 ** INSERT
@@ -393,10 +395,13 @@
395 **
396 ** Of particular importance for security is that this routine
397 ** disallows data changes on the "config" table, as that could
398 ** allow a malicious server to modify settings in such a way as
399 ** to cause a remote code execution.
400 **
401 ** Use the "fossil test-db-prepare --auth-ticket SQL" command to perform
402 ** manual testing of this authorizer.
403 */
404 static int ticket_schema_auth(
405 void *pNErr,
406 int eCode,
407 const char *z0,
@@ -403,10 +408,11 @@
408 const char *z1,
409 const char *z2,
410 const char *z3
411 ){
412 switch( eCode ){
413 case SQLITE_DROP_VIEW:
414 case SQLITE_CREATE_VIEW:
415 case SQLITE_CREATE_TABLE: {
416 if( sqlite3_stricmp(z2,"main")!=0
417 && sqlite3_stricmp(z2,"repository")!=0
418 ){
@@ -417,10 +423,11 @@
423 ){
424 goto ticket_schema_error;
425 }
426 break;
427 }
428 case SQLITE_DROP_INDEX:
429 case SQLITE_CREATE_INDEX: {
430 if( sqlite3_stricmp(z2,"main")!=0
431 && sqlite3_stricmp(z2,"repository")!=0
432 ){
433 goto ticket_schema_error;
@@ -463,10 +470,24 @@
470 ticket_schema_error:
471 if( pNErr ) *(int*)pNErr = 1;
472 return SQLITE_DENY;
473 }
474
475 /*
476 ** Activate the ticket schema authorizer. Must be followed by
477 ** an eventual call to ticket_unrestrict_sql().
478 */
479 void ticket_restrict_sql(int * pNErr){
480 db_set_authorizer(ticket_schema_auth,(void*)pNErr,"Ticket-Schema");
481 }
482 /*
483 ** Deactivate the ticket schema authorizer.
484 */
485 void ticket_unrestrict_sql(void){
486 db_clear_authorizer();
487 }
488
489
490 /*
491 ** Recreate the TICKET and TICKETCHNG tables.
492 */
493 void ticket_create_table(int separateConnection){
@@ -475,18 +496,18 @@
496 db_multi_exec(
497 "DROP TABLE IF EXISTS ticket;"
498 "DROP TABLE IF EXISTS ticketchng;"
499 );
500 zSql = ticket_table_schema();
501 ticket_restrict_sql(0);
502 if( separateConnection ){
503 if( db_transaction_nesting_depth() ) db_end_transaction(0);
504 db_init_database(g.zRepositoryName, zSql, 0);
505 }else{
506 db_multi_exec("%s", zSql/*safe-for-%s*/);
507 }
508 ticket_unrestrict_sql();
509 fossil_free(zSql);
510 }
511
512 /*
513 ** Repopulate the TICKET and TICKETCHNG tables from scratch using all
514

Keyboard Shortcuts

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