Fossil SCM

Fixed the 'add' Windows-reserved filename check to work with both filename and directory name input. It now always warns for such named s but permits them if --allow-reserved is used.

stephan 2021-03-26 19:32 trunk
Commit d0a8582e014d0a9fe749a58f90a6325eb8572a4686d35e6e0100f8d84e1fc110
3 files changed +28 -11 +19 +4 -7
+28 -11
--- src/add.c
+++ src/add.c
@@ -439,21 +439,10 @@
439439
Blob fullName = empty_blob;
440440
441441
/* file_tree_name() throws a fatal error if g.argv[i] is outside of the
442442
** checkout. */
443443
file_tree_name(g.argv[i], &fullName, 0, 1);
444
- if(0==allowReservedFlag
445
- && 0!=file_is_win_reserved(blob_str(&fullName))){
446
- /* Note that the 'add' internal machinery already _silently_
447
- ** skips over any names for which file_is_reserved_name()
448
- ** returns true or which is in the fossil_reserved_name()
449
- ** list. We do not need to warn for those, as they're outright
450
- ** verboten. */
451
- fossil_fatal("Filename is reserved: %b\n"
452
- "Use --allow-reserved to permit "
453
- "reserved filenames.", &fullName);
454
- }
455444
blob_reset(&fullName);
456445
file_canonical_name(g.argv[i], &fullName, 0);
457446
zName = blob_str(&fullName);
458447
isDir = file_isdir(zName, RepoFILE);
459448
if( isDir==1 ){
@@ -486,10 +475,38 @@
486475
blob_reset(&fullName);
487476
}
488477
glob_free(pIgnore);
489478
glob_free(pClean);
490479
480
+ /** Check for Windows-reserved names and warn or exit, as
481
+ ** appopriate. Note that the 'add' internal machinery already
482
+ ** _silently_ skips over any names for which
483
+ ** file_is_reserved_name() returns true or which is in the
484
+ ** fossil_reserved_name() list. We do not need to warn for those,
485
+ ** as they're outright verboten. */
486
+ if(db_exists("SELECT 1 FROM sfile WHERE win_reserved(pathname)")){
487
+ Stmt q = empty_Stmt;
488
+ db_prepare(&q,"SELECT pathname FROM sfile "
489
+ "WHERE win_reserved(pathname)");
490
+ int reservedCount = 0;
491
+ while( db_step(&q)==SQLITE_ROW ){
492
+ const char * zName = db_column_text(&q, 0);
493
+ ++reservedCount;
494
+ if(allowReservedFlag){
495
+ fossil_warning("WARNING: Windows-reserved "
496
+ "filename: %s", zName);
497
+ }else{
498
+ fossil_warning("ERROR: Windows-reserved filename: %s", zName);
499
+ }
500
+ }
501
+ db_finalize(&q);
502
+ if(allowReservedFlag==0){
503
+ fossil_fatal("ERROR: %d Windows-reserved filename(s) added. "
504
+ "Use --allow-reserved to permit such names.",
505
+ reservedCount);
506
+ }
507
+ }
491508
add_files_in_sfile(vid);
492509
db_end_transaction(0);
493510
}
494511
495512
/*
496513
--- src/add.c
+++ src/add.c
@@ -439,21 +439,10 @@
439 Blob fullName = empty_blob;
440
441 /* file_tree_name() throws a fatal error if g.argv[i] is outside of the
442 ** checkout. */
443 file_tree_name(g.argv[i], &fullName, 0, 1);
444 if(0==allowReservedFlag
445 && 0!=file_is_win_reserved(blob_str(&fullName))){
446 /* Note that the 'add' internal machinery already _silently_
447 ** skips over any names for which file_is_reserved_name()
448 ** returns true or which is in the fossil_reserved_name()
449 ** list. We do not need to warn for those, as they're outright
450 ** verboten. */
451 fossil_fatal("Filename is reserved: %b\n"
452 "Use --allow-reserved to permit "
453 "reserved filenames.", &fullName);
454 }
455 blob_reset(&fullName);
456 file_canonical_name(g.argv[i], &fullName, 0);
457 zName = blob_str(&fullName);
458 isDir = file_isdir(zName, RepoFILE);
459 if( isDir==1 ){
@@ -486,10 +475,38 @@
486 blob_reset(&fullName);
487 }
488 glob_free(pIgnore);
489 glob_free(pClean);
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491 add_files_in_sfile(vid);
492 db_end_transaction(0);
493 }
494
495 /*
496
--- src/add.c
+++ src/add.c
@@ -439,21 +439,10 @@
439 Blob fullName = empty_blob;
440
441 /* file_tree_name() throws a fatal error if g.argv[i] is outside of the
442 ** checkout. */
443 file_tree_name(g.argv[i], &fullName, 0, 1);
 
 
 
 
 
 
 
 
 
 
 
444 blob_reset(&fullName);
445 file_canonical_name(g.argv[i], &fullName, 0);
446 zName = blob_str(&fullName);
447 isDir = file_isdir(zName, RepoFILE);
448 if( isDir==1 ){
@@ -486,10 +475,38 @@
475 blob_reset(&fullName);
476 }
477 glob_free(pIgnore);
478 glob_free(pClean);
479
480 /** Check for Windows-reserved names and warn or exit, as
481 ** appopriate. Note that the 'add' internal machinery already
482 ** _silently_ skips over any names for which
483 ** file_is_reserved_name() returns true or which is in the
484 ** fossil_reserved_name() list. We do not need to warn for those,
485 ** as they're outright verboten. */
486 if(db_exists("SELECT 1 FROM sfile WHERE win_reserved(pathname)")){
487 Stmt q = empty_Stmt;
488 db_prepare(&q,"SELECT pathname FROM sfile "
489 "WHERE win_reserved(pathname)");
490 int reservedCount = 0;
491 while( db_step(&q)==SQLITE_ROW ){
492 const char * zName = db_column_text(&q, 0);
493 ++reservedCount;
494 if(allowReservedFlag){
495 fossil_warning("WARNING: Windows-reserved "
496 "filename: %s", zName);
497 }else{
498 fossil_warning("ERROR: Windows-reserved filename: %s", zName);
499 }
500 }
501 db_finalize(&q);
502 if(allowReservedFlag==0){
503 fossil_fatal("ERROR: %d Windows-reserved filename(s) added. "
504 "Use --allow-reserved to permit such names.",
505 reservedCount);
506 }
507 }
508 add_files_in_sfile(vid);
509 db_end_transaction(0);
510 }
511
512 /*
513
+19
--- src/db.c
+++ src/db.c
@@ -1376,10 +1376,13 @@
13761376
alert_display_name_func, 0, 0);
13771377
sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0,
13781378
db_obscure, 0, 0);
13791379
sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
13801380
db_protected_setting_func, 0, 0);
1381
+ sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
1382
+ db_win_reserved_func,0,0
1383
+ );
13811384
}
13821385
13831386
#if USE_SEE
13841387
/*
13851388
** This is a pointer to the saved database encryption key string.
@@ -2876,10 +2879,26 @@
28762879
assert( rc==0 || rc==1 );
28772880
if( sqlite3_value_type(argv[2-rc])==SQLITE_NULL ) rc = 1-rc;
28782881
sqlite3_result_value(context, argv[2-rc]);
28792882
}
28802883
}
2884
+
2885
+/*
2886
+** Implementation of the "win_reserved(X)" SQL function, a wrapper
2887
+** for file_is_win_reserved(X) which returns true if X is
2888
+** a Windows-reserved filename.
2889
+*/
2890
+LOCAL void db_win_reserved_func(
2891
+ sqlite3_context *context,
2892
+ int argc,
2893
+ sqlite3_value **argv
2894
+){
2895
+ const char * zName = (const char *)sqlite3_value_text(argv[0]);
2896
+ if( zName!=0 ){
2897
+ sqlite3_result_int(context, file_is_win_reserved(zName)!=0);
2898
+ }
2899
+}
28812900
28822901
/*
28832902
** Convert the input string into a artifact hash. Make a notation in the
28842903
** CONCEALED table so that the hash can be undo using the db_reveal()
28852904
** function at some later time.
28862905
--- src/db.c
+++ src/db.c
@@ -1376,10 +1376,13 @@
1376 alert_display_name_func, 0, 0);
1377 sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0,
1378 db_obscure, 0, 0);
1379 sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
1380 db_protected_setting_func, 0, 0);
 
 
 
1381 }
1382
1383 #if USE_SEE
1384 /*
1385 ** This is a pointer to the saved database encryption key string.
@@ -2876,10 +2879,26 @@
2876 assert( rc==0 || rc==1 );
2877 if( sqlite3_value_type(argv[2-rc])==SQLITE_NULL ) rc = 1-rc;
2878 sqlite3_result_value(context, argv[2-rc]);
2879 }
2880 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2881
2882 /*
2883 ** Convert the input string into a artifact hash. Make a notation in the
2884 ** CONCEALED table so that the hash can be undo using the db_reveal()
2885 ** function at some later time.
2886
--- src/db.c
+++ src/db.c
@@ -1376,10 +1376,13 @@
1376 alert_display_name_func, 0, 0);
1377 sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0,
1378 db_obscure, 0, 0);
1379 sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
1380 db_protected_setting_func, 0, 0);
1381 sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
1382 db_win_reserved_func,0,0
1383 );
1384 }
1385
1386 #if USE_SEE
1387 /*
1388 ** This is a pointer to the saved database encryption key string.
@@ -2876,10 +2879,26 @@
2879 assert( rc==0 || rc==1 );
2880 if( sqlite3_value_type(argv[2-rc])==SQLITE_NULL ) rc = 1-rc;
2881 sqlite3_result_value(context, argv[2-rc]);
2882 }
2883 }
2884
2885 /*
2886 ** Implementation of the "win_reserved(X)" SQL function, a wrapper
2887 ** for file_is_win_reserved(X) which returns true if X is
2888 ** a Windows-reserved filename.
2889 */
2890 LOCAL void db_win_reserved_func(
2891 sqlite3_context *context,
2892 int argc,
2893 sqlite3_value **argv
2894 ){
2895 const char * zName = (const char *)sqlite3_value_text(argv[0]);
2896 if( zName!=0 ){
2897 sqlite3_result_int(context, file_is_win_reserved(zName)!=0);
2898 }
2899 }
2900
2901 /*
2902 ** Convert the input string into a artifact hash. Make a notation in the
2903 ** CONCEALED table so that the hash can be undo using the db_reveal()
2904 ** function at some later time.
2905
+4 -7
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -146,12 +146,12 @@
146146
){
147147
gather_artifact_stats(1);
148148
}
149149
150150
/*
151
-** Add the content(), compress(), and decompress() SQL functions to
152
-** database connection db.
151
+** Add the content(), compress(), decompress(), and
152
+** gather_artifact_stats() SQL functions to database connection db.
153153
*/
154154
int add_content_sql_commands(sqlite3 *db){
155155
sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
156156
sqlcmd_content, 0, 0);
157157
sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
@@ -171,18 +171,18 @@
171171
**
172172
** These invoke the corresponding C routines.
173173
**
174174
** WARNING:
175175
** Do not instantiate these functions for any Fossil webpage or command
176
-** method of than the "fossil sql" command. If an attacker gains access
176
+** method other than the "fossil sql" command. If an attacker gains access
177177
** to these functions, he will be able to disable other defense mechanisms.
178178
**
179179
** This routines are for interactiving testing only. They are experimental
180180
** and undocumented (apart from this comments) and might go away or change
181181
** in future releases.
182182
**
183
-** 2020-11-29: This functions are now only available if the "fossil sql"
183
+** 2020-11-29: These functions are now only available if the "fossil sql"
184184
** command is started with the --test option.
185185
*/
186186
static void sqlcmd_db_protect(
187187
sqlite3_context *context,
188188
int argc,
@@ -204,13 +204,10 @@
204204
int argc,
205205
sqlite3_value **argv
206206
){
207207
if( !local_bSqlCmdTest ) db_protect_pop();
208208
}
209
-
210
-
211
-
212209
213210
/*
214211
** This is the "automatic extension" initializer that runs right after
215212
** the connection to the repository database is opened. Set up the
216213
** database connection to be more useful to the human operator.
217214
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -146,12 +146,12 @@
146 ){
147 gather_artifact_stats(1);
148 }
149
150 /*
151 ** Add the content(), compress(), and decompress() SQL functions to
152 ** database connection db.
153 */
154 int add_content_sql_commands(sqlite3 *db){
155 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
156 sqlcmd_content, 0, 0);
157 sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
@@ -171,18 +171,18 @@
171 **
172 ** These invoke the corresponding C routines.
173 **
174 ** WARNING:
175 ** Do not instantiate these functions for any Fossil webpage or command
176 ** method of than the "fossil sql" command. If an attacker gains access
177 ** to these functions, he will be able to disable other defense mechanisms.
178 **
179 ** This routines are for interactiving testing only. They are experimental
180 ** and undocumented (apart from this comments) and might go away or change
181 ** in future releases.
182 **
183 ** 2020-11-29: This functions are now only available if the "fossil sql"
184 ** command is started with the --test option.
185 */
186 static void sqlcmd_db_protect(
187 sqlite3_context *context,
188 int argc,
@@ -204,13 +204,10 @@
204 int argc,
205 sqlite3_value **argv
206 ){
207 if( !local_bSqlCmdTest ) db_protect_pop();
208 }
209
210
211
212
213 /*
214 ** This is the "automatic extension" initializer that runs right after
215 ** the connection to the repository database is opened. Set up the
216 ** database connection to be more useful to the human operator.
217
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -146,12 +146,12 @@
146 ){
147 gather_artifact_stats(1);
148 }
149
150 /*
151 ** Add the content(), compress(), decompress(), and
152 ** gather_artifact_stats() SQL functions to database connection db.
153 */
154 int add_content_sql_commands(sqlite3 *db){
155 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
156 sqlcmd_content, 0, 0);
157 sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
@@ -171,18 +171,18 @@
171 **
172 ** These invoke the corresponding C routines.
173 **
174 ** WARNING:
175 ** Do not instantiate these functions for any Fossil webpage or command
176 ** method other than the "fossil sql" command. If an attacker gains access
177 ** to these functions, he will be able to disable other defense mechanisms.
178 **
179 ** This routines are for interactiving testing only. They are experimental
180 ** and undocumented (apart from this comments) and might go away or change
181 ** in future releases.
182 **
183 ** 2020-11-29: These functions are now only available if the "fossil sql"
184 ** command is started with the --test option.
185 */
186 static void sqlcmd_db_protect(
187 sqlite3_context *context,
188 int argc,
@@ -204,13 +204,10 @@
204 int argc,
205 sqlite3_value **argv
206 ){
207 if( !local_bSqlCmdTest ) db_protect_pop();
208 }
 
 
 
209
210 /*
211 ** This is the "automatic extension" initializer that runs right after
212 ** the connection to the repository database is opened. Set up the
213 ** database connection to be more useful to the human operator.
214

Keyboard Shortcuts

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