Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | Merge miscellanous auxiliary defenses and security enhancements. This check-in is not needed to fix any problems that are not already fixed in version 2.12.1. It merely provides additional defense in depth. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
f741baa6be99434854b3ca8f20e95230 |
User & Date: | drh 2020-08-24 23:24:02 |
Original Comment: | Merge miscellanous auxiliary defenses and security enhancements. This check-in is not needed to fix any problems that are not already fixed in version 3.12.1. It merely provides additional defense in depth. |
2020-08-26
| ||
15:52 | Merge in trunk (check-in [f741baa6be]) ... (check-in: 5d4a57f2 user: george tags: wiki-history) | |
2020-08-26
| ||
15:52 | Merge in trunk (check-in [f741baa6be]) ... (check-in: 5d4a57f2 user: george tags: wiki-history) | |
2020-08-25
| ||
00:01 | Improvements to handling of line endings and BOM marks when doing a 3-way merge. ... (check-in: 88ff2642 user: drh tags: trunk) | |
2020-08-24
| ||
23:24 | Merge miscellanous auxiliary defenses and security enhancements. This check-in is not needed to fix any problems that are not already fixed in version 2.12.1. It merely provides additional defense in depth. ... (check-in: f741baa6 user: drh tags: trunk) | |
20:24 | Changed how fossil.confirmer pinSize option computes element width to be more robust in the face of CSS 'auto' width values. ... (check-in: 1f4143ba user: stephan tags: trunk) | |
00:24 | Merge changes from trunk. ... (Closed-Leaf check-in: 4a8bc878 user: drh tags: sec2020) | |
Changes to src/add.c.
︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | ** ** Omit any file whose name is pOmit. */ static int add_one_file( const char *zPath, /* Tree-name of file to add. */ int vid /* Add to this VFILE */ ){ if( !file_is_simple_pathname(zPath, 1) ){ fossil_warning("filename contains illegal characters: %s", zPath); return 0; } if( db_exists("SELECT 1 FROM vfile" " WHERE pathname=%Q %s", zPath, filename_collation()) ){ db_multi_exec("UPDATE vfile SET deleted=0" " WHERE pathname=%Q %s AND deleted", zPath, filename_collation()); }else{ char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); int isExe = file_isexe(zFullname, RepoFILE); | > > > > > | | | | > | | > > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | ** ** Omit any file whose name is pOmit. */ static int add_one_file( const char *zPath, /* Tree-name of file to add. */ int vid /* Add to this VFILE */ ){ int doSkip = 0; if( !file_is_simple_pathname(zPath, 1) ){ fossil_warning("filename contains illegal characters: %s", zPath); return 0; } if( db_exists("SELECT 1 FROM vfile" " WHERE pathname=%Q %s", zPath, filename_collation()) ){ db_multi_exec("UPDATE vfile SET deleted=0" " WHERE pathname=%Q %s AND deleted", zPath, filename_collation()); }else{ char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); int isExe = file_isexe(zFullname, RepoFILE); if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){ /* Do not add unsafe files to the vfile */ doSkip = 1; }else{ db_multi_exec( "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)" "VALUES(%d,0,0,0,%Q,%d,%d,NULL)", vid, zPath, isExe, file_islink(0)); } fossil_free(zFullname); } if( db_changes() && !doSkip ){ fossil_print("ADDED %s\n", zPath); return 1; }else{ fossil_print("SKIP %s\n", zPath); return 0; } } /* ** Add all files in the sfile temp table. ** ** Automatically exclude the repository file and any other files ** with reserved names. Also exclude files that are beneath an ** existing symlink. */ static int add_files_in_sfile(int vid){ const char *zRepo; /* Name of the repository database file */ int nAdd = 0; /* Number of files added */ int i; /* Loop counter */ const char *zReserved; /* Name of a reserved file */ Blob repoName; /* Treename of the repository */ |
︙ | ︙ | |||
206 207 208 209 210 211 212 | zRepo = blob_str(&repoName); } if( filenames_are_case_sensitive() ){ xCmp = fossil_strcmp; }else{ xCmp = fossil_stricmp; } | | > > > > > > > > > > > | | | | > | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | zRepo = blob_str(&repoName); } if( filenames_are_case_sensitive() ){ xCmp = fossil_strcmp; }else{ xCmp = fossil_stricmp; } db_prepare(&loop, "SELECT pathname FROM sfile" " WHERE pathname NOT IN (" "SELECT sfile.pathname FROM vfile, sfile" " WHERE vfile.islink" " AND NOT vfile.deleted" " AND sfile.pathname>(vfile.pathname||'/')" " AND sfile.pathname<(vfile.pathname||'0'))" " ORDER BY pathname"); while( db_step(&loop)==SQLITE_ROW ){ const char *zToAdd = db_column_text(&loop, 0); if( fossil_strcmp(zToAdd, zRepo)==0 ) continue; if( strchr(zToAdd,'/') ){ if( file_is_reserved_name(zToAdd, -1) ) continue; }else{ for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){ if( xCmp(zToAdd, zReserved)==0 ) break; } if( zReserved ) continue; } nAdd += add_one_file(zToAdd, vid); } db_finalize(&loop); blob_reset(&repoName); return nAdd; } |
︙ | ︙ |
Changes to src/alerts.c.
︙ | ︙ | |||
934 935 936 937 938 939 940 | /* ** SETTING: email-subname width=16 ** This is a short name used to identifies the repository in the Subject: ** line of email alerts. Traditionally this name is included in square ** brackets. Examples: "[fossil-src]", "[sqlite-src]". */ /* | | | | | | | 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 | /* ** SETTING: email-subname width=16 ** This is a short name used to identifies the repository in the Subject: ** line of email alerts. Traditionally this name is included in square ** brackets. Examples: "[fossil-src]", "[sqlite-src]". */ /* ** SETTING: email-send-method width=5 default=off sensitive ** Determine the method used to send email. Allowed values are ** "off", "relay", "pipe", "dir", "db", and "stdout". The "off" value ** means no email is ever sent. The "relay" value means emails are sent ** to an Mail Sending Agent using SMTP located at email-send-relayhost. ** The "pipe" value means email messages are piped into a command ** determined by the email-send-command setting. The "dir" value means ** emails are written to individual files in a directory determined ** by the email-send-dir setting. The "db" value means that emails ** are added to an SQLite database named by the* email-send-db setting. ** The "stdout" value writes email text to standard output, for debugging. */ /* ** SETTING: email-send-command width=40 sensitive ** This is a command to which outbound email content is piped when the ** email-send-method is set to "pipe". The command must extract ** recipient, sender, subject, and all other relevant information ** from the email header. */ /* ** SETTING: email-send-dir width=40 sensitive ** This is a directory into which outbound emails are written as individual ** files if the email-send-method is set to "dir". */ /* ** SETTING: email-send-db width=40 sensitive ** This is an SQLite database file into which outbound emails are written ** if the email-send-method is set to "db". */ /* ** SETTING: email-self width=40 ** This is the email address for the repository. Outbound emails add ** this email address as the "From:" field. */ /* ** SETTING: email-send-relayhost width=40 sensitive ** This is the hostname and TCP port to which output email messages ** are sent when email-send-method is "relay". There should be an ** SMTP server configured as a Mail Submission Agent listening on the ** designated host and port and all times. */ |
︙ | ︙ | |||
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 | if( nName==64 ){ db_multi_exec( "UPDATE subscriber SET sverified=1" " WHERE subscriberCode=hextoblob(%Q)", zName); if( db_get_boolean("selfreg-verify",0) ){ char *zNewCap = db_get("default-perms","u"); db_multi_exec( "UPDATE user" " SET cap=%Q" " WHERE cap='7' AND login=(" " SELECT suname FROM subscriber" " WHERE subscriberCode=hextoblob(%Q))", zNewCap, zName ); login_set_capabilities(zNewCap, 0); } @ <h1>Your email alert subscription has been verified!</h1> @ <p>Use the form below to update your subscription information.</p> @ <p>Hint: Bookmark this page so that you can more easily update @ your subscription information in the future</p> }else{ | > > | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 | if( nName==64 ){ db_multi_exec( "UPDATE subscriber SET sverified=1" " WHERE subscriberCode=hextoblob(%Q)", zName); if( db_get_boolean("selfreg-verify",0) ){ char *zNewCap = db_get("default-perms","u"); db_unprotect(PROTECT_USER); db_multi_exec( "UPDATE user" " SET cap=%Q" " WHERE cap='7' AND login=(" " SELECT suname FROM subscriber" " WHERE subscriberCode=hextoblob(%Q))", zNewCap, zName ); db_protect_pop(); login_set_capabilities(zNewCap, 0); } @ <h1>Your email alert subscription has been verified!</h1> @ <p>Use the form below to update your subscription information.</p> @ <p>Hint: Bookmark this page so that you can more easily update @ your subscription information in the future</p> }else{ |
︙ | ︙ |
Changes to src/allrepo.c.
︙ | ︙ | |||
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | blob_append_sql(&sql, "DELETE FROM global_config WHERE name GLOB '%s:%q'", useCheckouts?"ckout":"repo", blob_str(&fn) ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ db_multi_exec("%s", blob_sql_text(&sql)); } } db_end_transaction(0); blob_reset(&sql); blob_reset(&fn); blob_reset(&extra); return; | > > | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | blob_append_sql(&sql, "DELETE FROM global_config WHERE name GLOB '%s:%q'", useCheckouts?"ckout":"repo", blob_str(&fn) ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ db_unprotect(PROTECT_CONFIG); db_multi_exec("%s", blob_sql_text(&sql)); db_protect_pop(); } } db_end_transaction(0); blob_reset(&sql); blob_reset(&fn); blob_reset(&extra); return; |
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | blob_append_sql(&sql, "INSERT OR IGNORE INTO global_config(name,value)" "VALUES('repo:%q',1)", z ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ db_multi_exec("%s", blob_sql_text(&sql)); } } db_end_transaction(0); blob_reset(&sql); blob_reset(&fn); blob_reset(&extra); return; | > > | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | blob_append_sql(&sql, "INSERT OR IGNORE INTO global_config(name,value)" "VALUES('repo:%q',1)", z ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ db_unprotect(PROTECT_CONFIG); db_multi_exec("%s", blob_sql_text(&sql)); db_protect_pop(); } } db_end_transaction(0); blob_reset(&sql); blob_reset(&fn); blob_reset(&extra); return; |
︙ | ︙ | |||
426 427 428 429 430 431 432 433 434 435 436 | ** be found, remove those names from the ~/.fossil file. */ if( nToDel>0 ){ const char *zSql = "DELETE FROM global_config WHERE name IN toDel"; if( dryRunFlag ){ fossil_print("%s\n", zSql); }else{ db_multi_exec("%s", zSql /*safe-for-%s*/ ); } } } | > > | 430 431 432 433 434 435 436 437 438 439 440 441 442 | ** be found, remove those names from the ~/.fossil file. */ if( nToDel>0 ){ const char *zSql = "DELETE FROM global_config WHERE name IN toDel"; if( dryRunFlag ){ fossil_print("%s\n", zSql); }else{ db_unprotect(PROTECT_CONFIG); db_multi_exec("%s", zSql /*safe-for-%s*/ ); db_protect_pop(); } } } |
Changes to src/backoffice.c.
︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | ** ** No other process should start active backoffice processing until ** process (1) no longer exists and the current time exceeds (2). */ static void backofficeReadLease(Lease *pLease){ Stmt q; memset(pLease, 0, sizeof(*pLease)); db_prepare(&q, "SELECT value FROM repository.config" " WHERE name='backoffice'"); if( db_step(&q)==SQLITE_ROW ){ const char *z = db_column_text(&q,0); z = backofficeParseInt(z, &pLease->idCurrent); z = backofficeParseInt(z, &pLease->tmCurrent); z = backofficeParseInt(z, &pLease->idNext); backofficeParseInt(z, &pLease->tmNext); } db_finalize(&q); } /* ** Return a string that describes how long it has been since the ** last backoffice run. The string is obtained from fossil_malloc(). */ char *backoffice_last_run(void){ | > > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | ** ** No other process should start active backoffice processing until ** process (1) no longer exists and the current time exceeds (2). */ static void backofficeReadLease(Lease *pLease){ Stmt q; memset(pLease, 0, sizeof(*pLease)); db_unprotect(PROTECT_CONFIG); db_prepare(&q, "SELECT value FROM repository.config" " WHERE name='backoffice'"); if( db_step(&q)==SQLITE_ROW ){ const char *z = db_column_text(&q,0); z = backofficeParseInt(z, &pLease->idCurrent); z = backofficeParseInt(z, &pLease->tmCurrent); z = backofficeParseInt(z, &pLease->idNext); backofficeParseInt(z, &pLease->tmNext); } db_finalize(&q); db_protect_pop(); } /* ** Return a string that describes how long it has been since the ** last backoffice run. The string is obtained from fossil_malloc(). */ char *backoffice_last_run(void){ |
︙ | ︙ | |||
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | return mprintf("%z ago", human_readable_age(rAge)); } /* ** Write a lease to the backoffice property */ static void backofficeWriteLease(Lease *pLease){ db_multi_exec( "REPLACE INTO repository.config(name,value,mtime)" " VALUES('backoffice','%lld %lld %lld %lld',now())", pLease->idCurrent, pLease->tmCurrent, pLease->idNext, pLease->tmNext); } /* ** Check to see if the specified Win32 process is still alive. It ** should be noted that even if this function returns non-zero, the ** process may die before another operation on it can be completed. */ | > > | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | return mprintf("%z ago", human_readable_age(rAge)); } /* ** Write a lease to the backoffice property */ static void backofficeWriteLease(Lease *pLease){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO repository.config(name,value,mtime)" " VALUES('backoffice','%lld %lld %lld %lld',now())", pLease->idCurrent, pLease->tmCurrent, pLease->idNext, pLease->tmNext); db_protect_pop(); } /* ** Check to see if the specified Win32 process is still alive. It ** should be noted that even if this function returns non-zero, the ** process may die before another operation on it can be completed. */ |
︙ | ︙ |
Changes to src/captcha.c.
︙ | ︙ | |||
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | const char *zSecret; const char *z; Blob b; static char zRes[20]; zSecret = db_get("captcha-secret", 0); if( zSecret==0 ){ db_multi_exec( "REPLACE INTO config(name,value)" " VALUES('captcha-secret', lower(hex(randomblob(20))));" ); zSecret = db_get("captcha-secret", 0); assert( zSecret!=0 ); } blob_init(&b, 0, 0); blob_appendf(&b, "%s-%x", zSecret, seed); sha1sum_blob(&b, &b); z = blob_buffer(&b); | > > | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | const char *zSecret; const char *z; Blob b; static char zRes[20]; zSecret = db_get("captcha-secret", 0); if( zSecret==0 ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name,value)" " VALUES('captcha-secret', lower(hex(randomblob(20))));" ); db_protect_pop(); zSecret = db_get("captcha-secret", 0); assert( zSecret!=0 ); } blob_init(&b, 0, 0); blob_appendf(&b, "%s-%x", zSecret, seed); sha1sum_blob(&b, &b); z = blob_buffer(&b); |
︙ | ︙ |
Changes to src/checkin.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | /* ** Create a TEMP table named SFILE and add all unmanaged files named on ** the command-line to that table. If directories are named, then add ** all unmanaged files contained underneath those directories. If there ** are no files or directories named on the command-line, then add all ** unmanaged files anywhere in the checkout. */ static void locate_unmanaged_files( int argc, /* Number of command-line arguments to examine */ char **argv, /* values of command-line arguments */ unsigned scanFlags, /* Zero or more SCAN_xxx flags */ Glob *pIgnore /* Do not add files that match this GLOB */ ){ Blob name; /* Name of a candidate file or directory */ char *zName; /* Name of a candidate file or directory */ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */ int i; /* Loop counter */ int nRoot; /* length of g.zLocalRoot */ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s," " mtime INTEGER, size INTEGER)", filename_collation()); nRoot = (int)strlen(g.zLocalRoot); if( argc==0 ){ blob_init(&name, g.zLocalRoot, nRoot - 1); | > > > | | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* ** Create a TEMP table named SFILE and add all unmanaged files named on ** the command-line to that table. If directories are named, then add ** all unmanaged files contained underneath those directories. If there ** are no files or directories named on the command-line, then add all ** unmanaged files anywhere in the checkout. ** ** This routine never follows symlinks. It always treats symlinks as ** object unto themselves. */ static void locate_unmanaged_files( int argc, /* Number of command-line arguments to examine */ char **argv, /* values of command-line arguments */ unsigned scanFlags, /* Zero or more SCAN_xxx flags */ Glob *pIgnore /* Do not add files that match this GLOB */ ){ Blob name; /* Name of a candidate file or directory */ char *zName; /* Name of a candidate file or directory */ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */ int i; /* Loop counter */ int nRoot; /* length of g.zLocalRoot */ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s," " mtime INTEGER, size INTEGER)", filename_collation()); nRoot = (int)strlen(g.zLocalRoot); if( argc==0 ){ blob_init(&name, g.zLocalRoot, nRoot - 1); vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0, SymFILE); blob_reset(&name); }else{ for(i=0; i<argc; i++){ file_canonical_name(argv[i], &name, 0); zName = blob_str(&name); isDir = file_isdir(zName, SymFILE); if( isDir==1 ){ vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0, SymFILE); }else if( isDir==0 ){ fossil_warning("not found: %s", &zName[nRoot]); }else if( file_access(zName, R_OK) ){ fossil_fatal("cannot open %s", &zName[nRoot]); }else{ db_multi_exec( "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", |
︙ | ︙ | |||
854 855 856 857 858 859 860 | /* We should be done with options.. */ verify_all_options(); if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } pIgnore = glob_create(zIgnoreFlag); | < < | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 | /* We should be done with options.. */ verify_all_options(); if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } pIgnore = glob_create(zIgnoreFlag); locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore); glob_free(pIgnore); blob_zero(&report); status_report(&report, flags); if( blob_size(&report) ){ if( showHdr ){ |
︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 | } if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; verify_all_options(); pIgnore = glob_create(zIgnoreFlag); pKeep = glob_create(zKeepFlag); pClean = glob_create(zCleanFlag); nRoot = (int)strlen(g.zLocalRoot); | < < | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | } if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; verify_all_options(); pIgnore = glob_create(zIgnoreFlag); pKeep = glob_create(zKeepFlag); pClean = glob_create(zCleanFlag); nRoot = (int)strlen(g.zLocalRoot); if( !dirsOnlyFlag ){ Stmt q; Blob repo; if( !dryRunFlag && !disableUndo ) undo_begin(); locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore); db_prepare(&q, "SELECT %Q || pathname FROM sfile" |
︙ | ︙ | |||
2732 2733 2734 2735 2736 2737 2738 | undo_reset(); /* Commit */ db_multi_exec("DELETE FROM vvar WHERE name='ci-comment'"); db_multi_exec("PRAGMA repository.application_id=252006673;"); db_multi_exec("PRAGMA localdb.application_id=252006674;"); if( dryRunFlag ){ | < | 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 | undo_reset(); /* Commit */ db_multi_exec("DELETE FROM vvar WHERE name='ci-comment'"); db_multi_exec("PRAGMA repository.application_id=252006673;"); db_multi_exec("PRAGMA localdb.application_id=252006674;"); if( dryRunFlag ){ db_end_transaction(1); exit(1); } db_end_transaction(0); if( outputManifest & MFESTFLG_TAGS ){ Blob tagslist; |
︙ | ︙ |
Changes to src/clone.c.
︙ | ︙ | |||
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | /* If the --ssl-identity option was specified, store it as a setting */ Blob fn; blob_zero(&fn); file_canonical_name(g.zSSLIdentity, &fn, 0); db_set("ssl-identity", blob_str(&fn), 0); blob_reset(&fn); } db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('server-code', lower(hex(randomblob(20))), now());" "DELETE FROM config WHERE name='project-code';" ); url_enable_proxy(0); clone_ssh_db_set_options(); url_get_password_if_needed(); g.xlinkClusterOnly = 1; nErr = client_sync(syncFlags,CONFIGSET_ALL,0,0); g.xlinkClusterOnly = 0; verify_cancel(); | > > | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | /* If the --ssl-identity option was specified, store it as a setting */ Blob fn; blob_zero(&fn); file_canonical_name(g.zSSLIdentity, &fn, 0); db_set("ssl-identity", blob_str(&fn), 0); blob_reset(&fn); } db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('server-code', lower(hex(randomblob(20))), now());" "DELETE FROM config WHERE name='project-code';" ); db_protect_pop(); url_enable_proxy(0); clone_ssh_db_set_options(); url_get_password_if_needed(); g.xlinkClusterOnly = 1; nErr = client_sync(syncFlags,CONFIGSET_ALL,0,0); g.xlinkClusterOnly = 0; verify_cancel(); |
︙ | ︙ | |||
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | } db_end_transaction(0); fossil_print("Vacuuming the database... "); fflush(stdout); if( db_int(0, "PRAGMA page_count")>1000 && db_int(0, "PRAGMA page_size")<8192 ){ db_multi_exec("PRAGMA page_size=8192;"); } db_multi_exec("VACUUM"); fossil_print("\nproject-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); } /* | > > | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | } db_end_transaction(0); fossil_print("Vacuuming the database... "); fflush(stdout); if( db_int(0, "PRAGMA page_count")>1000 && db_int(0, "PRAGMA page_size")<8192 ){ db_multi_exec("PRAGMA page_size=8192;"); } db_unprotect(PROTECT_ALL); db_multi_exec("VACUUM"); db_protect_pop(); fossil_print("\nproject-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); } /* |
︙ | ︙ |
Changes to src/configure.c.
︙ | ︙ | |||
143 144 145 146 147 148 149 | { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, | < | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, { "parent-project-code", CONFIGSET_PROJ }, { "parent-project-name", CONFIGSET_PROJ }, { "hash-policy", CONFIGSET_PROJ }, { "comment-format", CONFIGSET_PROJ }, { "mimetypes", CONFIGSET_PROJ }, { "forbid-delta-manifests", CONFIGSET_PROJ }, |
︙ | ︙ | |||
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | blob_append_sql(&sql, ",\"%w\"", azToken[jj]); } blob_append_sql(&sql,") VALUES(%s,%s", azToken[1] /*safe-for-%s*/, azToken[0]/*safe-for-%s*/); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/); } db_multi_exec("%s)", blob_sql_text(&sql)); if( db_changes()==0 ){ blob_reset(&sql); blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s", &zName[1], azToken[0]/*safe-for-%s*/); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ", \"%w\"=%s", azToken[jj], azToken[jj+1]/*safe-for-%s*/); } blob_append_sql(&sql, " WHERE \"%w\"=%s AND mtime<%s", aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/, azToken[0]/*safe-for-%s*/); db_multi_exec("%s", blob_sql_text(&sql)); } blob_reset(&sql); rebuildMask |= thisMask; } } /* ** Process a file full of "config" cards. | > > | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | blob_append_sql(&sql, ",\"%w\"", azToken[jj]); } blob_append_sql(&sql,") VALUES(%s,%s", azToken[1] /*safe-for-%s*/, azToken[0]/*safe-for-%s*/); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/); } db_protect_only(PROTECT_SENSITIVE); db_multi_exec("%s)", blob_sql_text(&sql)); if( db_changes()==0 ){ blob_reset(&sql); blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s", &zName[1], azToken[0]/*safe-for-%s*/); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ", \"%w\"=%s", azToken[jj], azToken[jj+1]/*safe-for-%s*/); } blob_append_sql(&sql, " WHERE \"%w\"=%s AND mtime<%s", aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/, azToken[0]/*safe-for-%s*/); db_multi_exec("%s", blob_sql_text(&sql)); } db_protect_pop(); blob_reset(&sql); rebuildMask |= thisMask; } } /* ** Process a file full of "config" cards. |
︙ | ︙ | |||
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); db_begin_transaction(); export_config(mask, g.argv[3], 0, zBackup); for(i=0; i<count(aConfig); i++){ const char *zName = aConfig[i].zName; if( (aConfig[i].groupMask & mask)==0 ) continue; if( zName[0]!='@' ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); }else if( fossil_strcmp(zName,"@user")==0 ){ db_multi_exec("DELETE FROM user"); db_create_default_users(0, 0); }else if( fossil_strcmp(zName,"@concealed")==0 ){ db_multi_exec("DELETE FROM concealed"); }else if( fossil_strcmp(zName,"@shun")==0 ){ db_multi_exec("DELETE FROM shun"); }else if( fossil_strcmp(zName,"@subscriber")==0 ){ if( db_table_exists("repository","subscriber") ){ | > > > > | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); db_begin_transaction(); export_config(mask, g.argv[3], 0, zBackup); for(i=0; i<count(aConfig); i++){ const char *zName = aConfig[i].zName; if( (aConfig[i].groupMask & mask)==0 ) continue; if( zName[0]!='@' ){ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name=%Q", zName); db_protect_pop(); }else if( fossil_strcmp(zName,"@user")==0 ){ db_unprotect(PROTECT_USER); db_multi_exec("DELETE FROM user"); db_protect_pop(); db_create_default_users(0, 0); }else if( fossil_strcmp(zName,"@concealed")==0 ){ db_multi_exec("DELETE FROM concealed"); }else if( fossil_strcmp(zName,"@shun")==0 ){ db_multi_exec("DELETE FROM shun"); }else if( fossil_strcmp(zName,"@subscriber")==0 ){ if( db_table_exists("repository","subscriber") ){ |
︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 | if( zBlob ) fossil_fatal("cannot do both --file or --blob"); blob_read_from_file(&x, zFile, ExtFILE); }else if( zBlob ){ blob_read_from_file(&x, zBlob, ExtFILE); }else{ blob_init(&x,g.argv[3],-1); } db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" "VALUES(%Q,:val,now())", zVar); if( zBlob ){ db_bind_blob(&ins, ":val", &x); }else{ db_bind_text(&ins, ":val", blob_str(&x)); } db_step(&ins); db_finalize(&ins); blob_reset(&x); } | > > | 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | if( zBlob ) fossil_fatal("cannot do both --file or --blob"); blob_read_from_file(&x, zFile, ExtFILE); }else if( zBlob ){ blob_read_from_file(&x, zBlob, ExtFILE); }else{ blob_init(&x,g.argv[3],-1); } db_unprotect(PROTECT_CONFIG); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" "VALUES(%Q,:val,now())", zVar); if( zBlob ){ db_bind_blob(&ins, ":val", &x); }else{ db_bind_text(&ins, ":val", blob_str(&x)); } db_step(&ins); db_finalize(&ins); db_protect_pop(); blob_reset(&x); } |
Changes to src/db.c.
︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 | */ #define empty_Stmt_m {BLOB_INITIALIZER,NULL, NULL, NULL, 0, 0} #endif /* INTERFACE */ const struct Stmt empty_Stmt = empty_Stmt_m; /* ** Call this routine when a database error occurs. */ static void db_err(const char *zFormat, ...){ va_list ap; char *z; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); | > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | */ #define empty_Stmt_m {BLOB_INITIALIZER,NULL, NULL, NULL, 0, 0} #endif /* INTERFACE */ const struct Stmt empty_Stmt = empty_Stmt_m; /* ** Call this routine when a database error occurs. ** This routine throws a fatal error. It does not return. */ static void db_err(const char *zFormat, ...){ va_list ap; char *z; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); |
︙ | ︙ | |||
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | } /* ** All static variable that a used by only this file are gathered into ** the following structure. */ static struct DbLocalData { int nBegin; /* Nesting depth of BEGIN */ int doRollback; /* True to force a rollback */ int nCommitHook; /* Number of commit hooks */ int wrTxn; /* Outer-most TNX is a write */ Stmt *pAllStmt; /* List of all unfinalized statements */ int nPrepare; /* Number of calls to sqlite3_prepare_v2() */ int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */ struct sCommitHook { int (*xHook)(void); /* Functions to call at db_end_transaction() */ int sequence; /* Call functions in sequence order */ } aHook[5]; char *azDeleteOnFail[3]; /* Files to delete on a failure */ char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ int nBeforeCommit; /* Number of entries in azBeforeCommit */ int nPriorChanges; /* sqlite3_total_changes() at transaction start */ const char *zStartFile; /* File in which transaction was started */ int iStartLine; /* Line of zStartFile where transaction started */ | > > > > > > > > > | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | } /* ** All static variable that a used by only this file are gathered into ** the following structure. */ static struct DbLocalData { unsigned protectMask; /* Prevent changes to database */ int nBegin; /* Nesting depth of BEGIN */ int doRollback; /* True to force a rollback */ int nCommitHook; /* Number of commit hooks */ int wrTxn; /* Outer-most TNX is a write */ Stmt *pAllStmt; /* List of all unfinalized statements */ int nPrepare; /* Number of calls to sqlite3_prepare_v2() */ int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */ struct sCommitHook { int (*xHook)(void); /* Functions to call at db_end_transaction() */ int sequence; /* Call functions in sequence order */ } aHook[5]; char *azDeleteOnFail[3]; /* Files to delete on a failure */ char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ int nBeforeCommit; /* Number of entries in azBeforeCommit */ int nPriorChanges; /* sqlite3_total_changes() at transaction start */ const char *zStartFile; /* File in which transaction was started */ int iStartLine; /* Line of zStartFile where transaction started */ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); void *pAuthArg; /* Argument to the authorizer */ const char *zAuthName; /* Name of the authorizer */ int bProtectTriggers; /* True if protection triggers already exist */ int nProtect; /* Slots of aProtect used */ unsigned aProtect[10]; /* Saved values of protectMask */ } db = { PROTECT_USER|PROTECT_CONFIG|PROTECT_BASELINE, /* protectMask */ 0, 0, 0, 0, 0, 0, }; /* ** Arrange for the given file to be deleted on a failure. */ void db_delete_on_failure(const char *zFilename){ assert( db.nDeleteOnFail<count(db.azDeleteOnFail) ); if( zFilename==0 ) return; |
︙ | ︙ | |||
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | if( g.fSqlTrace ) fossil_trace("-- ROLLBACK by request\n"); } db.nBegin--; if( db.nBegin==0 ){ int i; if( db.doRollback==0 && db.nPriorChanges<sqlite3_total_changes(g.db) ){ i = 0; while( db.nBeforeCommit ){ db.nBeforeCommit--; sqlite3_exec(g.db, db.azBeforeCommit[i], 0, 0, 0); sqlite3_free(db.azBeforeCommit[i]); i++; } leaf_do_pending_checks(); } for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){ int rc = db.aHook[i].xHook(); if( rc ){ db.doRollback = 1; if( g.fSqlTrace ) fossil_trace("-- ROLLBACK due to aHook[%d]\n", i); } | > > | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | if( g.fSqlTrace ) fossil_trace("-- ROLLBACK by request\n"); } db.nBegin--; if( db.nBegin==0 ){ int i; if( db.doRollback==0 && db.nPriorChanges<sqlite3_total_changes(g.db) ){ i = 0; db_protect_only(PROTECT_SENSITIVE); while( db.nBeforeCommit ){ db.nBeforeCommit--; sqlite3_exec(g.db, db.azBeforeCommit[i], 0, 0, 0); sqlite3_free(db.azBeforeCommit[i]); i++; } leaf_do_pending_checks(); db_protect_pop(); } for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){ int rc = db.aHook[i].xHook(); if( rc ){ db.doRollback = 1; if( g.fSqlTrace ) fossil_trace("-- ROLLBACK due to aHook[%d]\n", i); } |
︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | db.aHook[i].xHook = xS; } } db.aHook[db.nCommitHook].sequence = sequence; db.aHook[db.nCommitHook].xHook = x; db.nCommitHook++; } #if INTERFACE /* ** Possible flags to db_vprepare */ #define DB_PREPARE_IGNORE_ERROR 0x001 /* Suppress errors */ #define DB_PREPARE_PERSISTENT 0x002 /* Stmt will stick around for a while */ #endif /* ** Prepare a Stmt. Assume that the Stmt is previously uninitialized. ** If the input string contains multiple SQL statements, only the first ** one is processed. All statements beyond the first are silently ignored. */ int db_vprepare(Stmt *pStmt, int flags, const char *zFormat, va_list ap){ int rc; int prepFlags = 0; char *zSql; blob_zero(&pStmt->sql); blob_vappendf(&pStmt->sql, zFormat, ap); va_end(ap); zSql = blob_str(&pStmt->sql); db.nPrepare++; if( flags & DB_PREPARE_PERSISTENT ){ prepFlags = SQLITE_PREPARE_PERSISTENT; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | db.aHook[i].xHook = xS; } } db.aHook[db.nCommitHook].sequence = sequence; db.aHook[db.nCommitHook].xHook = x; db.nCommitHook++; } #if INTERFACE /* ** Flag bits for db_protect() and db_unprotect() indicating which parts ** of the databases should be write protected or write enabled, respectively. */ #define PROTECT_USER 0x01 /* USER table */ #define PROTECT_CONFIG 0x02 /* CONFIG and GLOBAL_CONFIG tables */ #define PROTECT_SENSITIVE 0x04 /* Sensitive and/or global settings */ #define PROTECT_READONLY 0x08 /* everything except TEMP tables */ #define PROTECT_BASELINE 0x10 /* protection system is working */ #define PROTECT_ALL 0x1f /* All of the above */ #define PROTECT_NONE 0x00 /* Nothing. Everything is open */ #endif /* INTERFACE */ /* ** Enable or disable database write protections. ** ** db_protext(X) Add protects on X ** db_unprotect(X) Remove protections on X ** db_protect_only(X) Remove all prior protections then set ** protections to only X. ** ** Each of these routines pushes the previous protection mask onto ** a finite-size stack. Each should be followed by a call to ** db_protect_pop() to pop the stack and restore the protections that ** existed prior to the call. The protection mask stack has a limited ** depth, so take care not to next calls too deeply. ** ** About Database Write Protection ** ------------------------------- ** ** This is *not* a primary means of defending the application from ** attack. Fossil should be secure even if this mechanism is disabled. ** The purpose of database write protection is to provide an additional ** layer of defense in case SQL injection bugs somehow slip into other ** parts of the system. In other words, database write protection is ** not primary defense but rather defense in depth. ** ** This mechanism mostly focuses on the USER table, to prevent an ** attacker from giving themselves Admin privilegs, and on the ** CONFIG table and specially "sensitive" settings such as ** "diff-command" or "editor" that if compromised by an attacker ** could lead to an RCE. ** ** By default, the USER and CONFIG tables are read-only. Various ** subsystems that legitimately need to change those tables can ** temporarily do so using: ** ** db_unprotect(PROTECT_xxx); ** // make the legitmate changes here ** db_protect_pop(); ** ** Code that runs inside of reduced protections should be carefully ** reviewed to ensure that it is harmless and not subject to SQL ** injection. ** ** Read-only operations (such as many web pages like /timeline) ** can invoke db_protect(PROTECT_ALL) to effectively make the database ** read-only. TEMP tables (which are often used for these kinds of ** pages) are still writable, however. ** ** The PROTECT_SENSITIVE protection is a subset of PROTECT_CONFIG ** that blocks changes to all of the global_config table, but only ** "sensitive" settings in the config table. PROTECT_SENSITIVE ** relies on triggers and the protected_setting() SQL function to ** prevent changes to sensitive settings. ** ** Additional Notes ** ---------------- ** ** Calls to routines like db_set() and db_unset() temporarily disable ** the PROTECT_CONFIG protection. The assumption is that these calls ** cannot be invoked by an SQL injection and are thus safe. Make sure ** this is the case by always using a string literal as the name argument ** to db_set() and db_unset() and friend, not a variable that might ** be compromised by an attack. */ void db_protect_only(unsigned flags){ if( db.nProtect>=count(db.aProtect)-2 ){ fossil_panic("too many db_protect() calls"); } db.aProtect[db.nProtect++] = db.protectMask; if( (flags & PROTECT_SENSITIVE)!=0 && db.bProtectTriggers==0 && g.repositoryOpen ){ /* Create the triggers needed to protect sensitive settings from ** being created or modified the first time that PROTECT_SENSITIVE ** is enabled. Deleting a sensitive setting is harmless, so there ** is not trigger to block deletes. After being created once, the ** triggers persist for the life of the database connection. */ db_multi_exec( "CREATE TEMP TRIGGER protect_1 BEFORE INSERT ON config" " WHEN protected_setting(new.name) BEGIN" " SELECT raise(abort,'not authorized');" "END;\n" "CREATE TEMP TRIGGER protect_2 BEFORE UPDATE ON config" " WHEN protected_setting(new.name) BEGIN" " SELECT raise(abort,'not authorized');" "END;\n" ); db.bProtectTriggers = 1; } db.protectMask = flags; } void db_protect(unsigned flags){ db_protect_only(db.protectMask | flags); } void db_unprotect(unsigned flags){ if( db.nProtect>=count(db.aProtect)-2 ){ fossil_panic("too many db_unprotect() calls"); } db.aProtect[db.nProtect++] = db.protectMask; db.protectMask &= ~flags; } void db_protect_pop(void){ if( db.nProtect<1 ){ fossil_panic("too many db_protect_pop() calls"); } db.protectMask = db.aProtect[--db.nProtect]; } /* ** Verify that the desired database write pertections are in place. ** Throw a fatal error if not. */ void db_assert_protected(unsigned flags){ if( (flags & db.protectMask)!=flags ){ fossil_panic("missing database write protection bits: %02x", flags & ~db.protectMask); } } /* ** Assert that either all protections are off (including PROTECT_BASELINE ** which is usually always enabled), or the setting named in the argument ** is no a sensitive setting. ** ** This assert() is used to verify that the db_set() and db_set_int() ** interfaces do not modify a sensitive setting. */ void db_assert_protection_off_or_not_sensitive(const char *zName){ if( db.protectMask!=0 && db_setting_is_protected(zName) ){ fossil_panic("unauthorized change to protected setting \"%s\"", zName); } } /* ** Every Fossil database connection automatically registers the following ** overarching authenticator callback, and leaves it registered for the ** duration of the connection. This authenticator will call any ** sub-authenticators that are registered using db_set_authorizer(). */ int db_top_authorizer( void *pNotUsed, int eCode, const char *z0, const char *z1, const char *z2, const char *z3 ){ int rc = SQLITE_OK; switch( eCode ){ case SQLITE_INSERT: case SQLITE_UPDATE: case SQLITE_DELETE: { if( (db.protectMask & PROTECT_USER)!=0 && sqlite3_stricmp(z0,"user")==0 ){ rc = SQLITE_DENY; }else if( (db.protectMask & PROTECT_CONFIG)!=0 && (sqlite3_stricmp(z0,"config")==0 || sqlite3_stricmp(z0,"global_config")==0) ){ rc = SQLITE_DENY; }else if( (db.protectMask & PROTECT_SENSITIVE)!=0 && sqlite3_stricmp(z0,"global_config")==0 ){ rc = SQLITE_DENY; }else if( (db.protectMask & PROTECT_READONLY)!=0 && sqlite3_stricmp(z2,"temp")!=0 ){ rc = SQLITE_DENY; } break; } case SQLITE_DROP_TEMP_TRIGGER: { /* Do not allow the triggers that enforce PROTECT_SENSITIVE ** to be dropped */ rc = SQLITE_DENY; break; } } if( db.xAuth && rc==SQLITE_OK ){ rc = db.xAuth(db.pAuthArg, eCode, z0, z1, z2, z3); } return rc; } /* ** Set or unset the query authorizer callback function */ void db_set_authorizer( int(*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg, const char *zName /* for tracing */ ){ if( db.xAuth ){ fossil_panic("multiple active db_set_authorizer() calls"); } db.xAuth = xAuth; db.pAuthArg = pArg; db.zAuthName = zName; if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName); } void db_clear_authorizer(void){ if( db.zAuthName && g.fSqlTrace ){ fossil_trace("-- discontinue authorizer %s\n", db.zAuthName); } db.xAuth = 0; db.pAuthArg = 0; db.zAuthName = 0; } #if INTERFACE /* ** Possible flags to db_vprepare */ #define DB_PREPARE_IGNORE_ERROR 0x001 /* Suppress errors */ #define DB_PREPARE_PERSISTENT 0x002 /* Stmt will stick around for a while */ #endif /* ** Prepare a Stmt. Assume that the Stmt is previously uninitialized. ** If the input string contains multiple SQL statements, only the first ** one is processed. All statements beyond the first are silently ignored. */ int db_vprepare(Stmt *pStmt, int flags, const char *zFormat, va_list ap){ int rc; int prepFlags = 0; char *zSql; const char *zExtra = 0; blob_zero(&pStmt->sql); blob_vappendf(&pStmt->sql, zFormat, ap); va_end(ap); zSql = blob_str(&pStmt->sql); db.nPrepare++; if( flags & DB_PREPARE_PERSISTENT ){ prepFlags = SQLITE_PREPARE_PERSISTENT; } rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, &zExtra); if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){ db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); }else if( zExtra && !fossil_all_whitespace(zExtra) ){ db_err("surplus text follows SQL: \"%s\"", zExtra); } pStmt->pNext = db.pAllStmt; pStmt->pPrev = 0; if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt; db.pAllStmt = pStmt; pStmt->nStep = 0; pStmt->rc = rc; |
︙ | ︙ | |||
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | rc = db_reset(pStmt); db_check_result(rc, pStmt); return rc; } /* ** COMMAND: test-db-exec-error ** ** Invoke the db_exec() interface with an erroneous SQL statement ** in order to verify the error handling logic. */ void db_test_db_exec_cmd(void){ Stmt err; db_find_and_open_repository(0,0); db_prepare(&err, "INSERT INTO repository.config(name) VALUES(NULL);"); db_exec(&err); } /* ** Print the output of one or more SQL queries on standard output. ** This routine is used for debugging purposes only. */ int db_debug(const char *zSql, ...){ Blob sql; | > > > > > > > > > > > > > > > > > > | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 | rc = db_reset(pStmt); db_check_result(rc, pStmt); return rc; } /* ** COMMAND: test-db-exec-error ** Usage: %fossil test-db-exec-error ** ** Invoke the db_exec() interface with an erroneous SQL statement ** in order to verify the error handling logic. */ void db_test_db_exec_cmd(void){ Stmt err; db_find_and_open_repository(0,0); db_prepare(&err, "INSERT INTO repository.config(name) VALUES(NULL);"); db_exec(&err); } /* ** COMMAND: test-db-prepare ** Usage: %fossil test-db-prepare ?OPTIONS? SQL ** ** Invoke db_prepare() on the SQL input. Report any errors encountered. ** This command is used to verify error detection logic in the db_prepare() ** utility routine. */ void db_test_db_prepare(void){ Stmt err; db_find_and_open_repository(0,0); verify_all_options(); if( g.argc!=3 ) usage("?OPTIONS? SQL"); db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/); db_finalize(&err); } /* ** Print the output of one or more SQL queries on standard output. ** This routine is used for debugging purposes only. */ int db_debug(const char *zSql, ...){ Blob sql; |
︙ | ︙ | |||
842 843 844 845 846 847 848 | ** database. */ void db_init_database( const char *zFileName, /* Name of database file to create */ const char *zSchema, /* First part of schema */ ... /* Additional SQL to run. Terminate with NULL. */ ){ | | | | | | | | | | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | ** database. */ void db_init_database( const char *zFileName, /* Name of database file to create */ const char *zSchema, /* First part of schema */ ... /* Additional SQL to run. Terminate with NULL. */ ){ sqlite3 *xdb; int rc; const char *zSql; va_list ap; xdb = db_open(zFileName ? zFileName : ":memory:"); sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0); rc = sqlite3_exec(xdb, zSchema, 0, 0, 0); if( rc!=SQLITE_OK ){ db_err("%s", sqlite3_errmsg(xdb)); } va_start(ap, zSchema); while( (zSql = va_arg(ap, const char*))!=0 ){ rc = sqlite3_exec(xdb, zSql, 0, 0, 0); if( rc!=SQLITE_OK ){ db_err("%s", sqlite3_errmsg(xdb)); } } va_end(ap); sqlite3_exec(xdb, "COMMIT", 0, 0, 0); if( zFileName || g.db!=0 ){ sqlite3_close(xdb); }else{ g.db = xdb; } } /* ** Function to return the number of seconds since 1970. This is ** the same as strftime('%s','now') but is more compact. */ |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 | sqlite3_result_error_nomem(context); return; } strcpy(zOut, zTemp = obscure((char*)zIn)); fossil_free(zTemp); sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free); } /* ** Register the SQL functions that are useful both to the internal ** representation and to the "fossil sql" command. */ void db_add_aux_functions(sqlite3 *db){ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 | sqlite3_result_error_nomem(context); return; } strcpy(zOut, zTemp = obscure((char*)zIn)); fossil_free(zTemp); sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free); } /* ** Return True if zName is a protected (a.k.a. "sensitive") setting. */ int db_setting_is_protected(const char *zName){ const Setting *pSetting = zName ? db_find_setting(zName,0) : 0; return pSetting!=0 && pSetting->sensitive!=0; } /* ** Implement the protected_setting(X) SQL function. This function returns ** true if X is the name of a protected (security-sensitive) setting and ** the db.protectSensitive flag is enabled. It returns false otherwise. */ LOCAL void db_protected_setting_func( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSetting; if( (db.protectMask & PROTECT_SENSITIVE)==0 ){ sqlite3_result_int(context, 0); return; } zSetting = (const char*)sqlite3_value_text(argv[0]); sqlite3_result_int(context, db_setting_is_protected(zSetting)); } /* ** Register the SQL functions that are useful both to the internal ** representation and to the "fossil sql" command. */ void db_add_aux_functions(sqlite3 *db){ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, |
︙ | ︙ | |||
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 | capability_fullcap, 0, 0); sqlite3_create_function(db, "find_emailaddr", 1, SQLITE_UTF8, 0, alert_find_emailaddr_func, 0, 0); sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0, alert_display_name_func, 0, 0); sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0, db_obscure, 0, 0); } #if USE_SEE /* ** This is a pointer to the saved database encryption key string. */ static char *zSavedKey = 0; | > > | 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 | capability_fullcap, 0, 0); sqlite3_create_function(db, "find_emailaddr", 1, SQLITE_UTF8, 0, alert_find_emailaddr_func, 0, 0); sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0, alert_display_name_func, 0, 0); sqlite3_create_function(db, "obscure", 1, SQLITE_UTF8, 0, db_obscure, 0, 0); sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0, db_protected_setting_func, 0, 0); } #if USE_SEE /* ** This is a pointer to the saved database encryption key string. */ static char *zSavedKey = 0; |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 | db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0 ); if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0); db_add_aux_functions(db); re_add_sql_func(db); /* The REGEXP operator */ foci_register(db); /* The "files_of_checkin" virtual table */ sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc); return db; } /* ** Detaches the zLabel database. */ | > | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 | db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0 ); if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0); db_add_aux_functions(db); re_add_sql_func(db); /* The REGEXP operator */ foci_register(db); /* The "files_of_checkin" virtual table */ sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc); sqlite3_set_authorizer(db, db_top_authorizer, db); return db; } /* ** Detaches the zLabel database. */ |
︙ | ︙ | |||
1789 1790 1791 1792 1793 1794 1795 | zRepo = file_canonical_name_dup(zFree); fossil_free(zFree); } } return zRepo; } | < < < < < < < < < < < < | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 | zRepo = file_canonical_name_dup(zFree); fossil_free(zFree); } } return zRepo; } /* ** Returns non-zero if support for symlinks is currently enabled. */ int db_allow_symlinks(void){ return g.allowSymlinks; } |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 1853 | } } g.zRepositoryName = mprintf("%s", zDbName); db_open_or_attach(g.zRepositoryName, "repository"); g.repositoryOpen = 1; sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION, &g.iRepoDataVers); /* Cache "allow-symlinks" option, because we'll need it on every stat call */ | > | | | 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 | } } g.zRepositoryName = mprintf("%s", zDbName); db_open_or_attach(g.zRepositoryName, "repository"); g.repositoryOpen = 1; sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION, &g.iRepoDataVers); /* Cache "allow-symlinks" option, because we'll need it on every stat call */ g.allowSymlinks = db_get_boolean("allow-symlinks",0); g.zAuxSchema = db_get("aux-schema",""); g.eHashPolicy = db_get_int("hash-policy",-1); if( g.eHashPolicy<0 ){ g.eHashPolicy = hname_default_policy(); db_set_int("hash-policy", g.eHashPolicy, 0); } |
︙ | ︙ | |||
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 | ** ** Check for unfinalized statements and report errors if the reportErrors ** argument is true. Ignore unfinalized statements when false. */ void db_close(int reportErrors){ sqlite3_stmt *pStmt; if( g.db==0 ) return; if( g.fSqlStats ){ int cur, hiwtr; sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0); fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr); sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0); fprintf(stderr, "-- LOOKASIDE_HIT %10d\n", hiwtr); sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &cur,&hiwtr,0); | > | 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 | ** ** Check for unfinalized statements and report errors if the reportErrors ** argument is true. Ignore unfinalized statements when false. */ void db_close(int reportErrors){ sqlite3_stmt *pStmt; if( g.db==0 ) return; sqlite3_set_authorizer(g.db, 0, 0); if( g.fSqlStats ){ int cur, hiwtr; sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0); fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr); sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0); fprintf(stderr, "-- LOOKASIDE_HIT %10d\n", hiwtr); sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &cur,&hiwtr,0); |
︙ | ︙ | |||
2116 2117 2118 2119 2120 2121 2122 | sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0); fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr); fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare); } while( db.pAllStmt ){ db_finalize(db.pAllStmt); } | | > | | > > | > > > > | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 | sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0); fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr); fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare); } while( db.pAllStmt ){ db_finalize(db.pAllStmt); } if( db.nBegin ){ if( reportErrors ){ fossil_warning("Transaction started at %s:%d never commits", db.zStartFile, db.iStartLine); } db_end_transaction(1); } pStmt = 0; sqlite3_busy_timeout(g.db, 0); g.dbIgnoreErrors++; /* Stop "database locked" warnings */ sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0); g.dbIgnoreErrors--; db_close_config(); /* If the localdb has a lot of unused free space, ** then VACUUM it as we shut down. */ if( db_database_slot("localdb")>=0 ){ int nFree = db_int(0, "PRAGMA localdb.freelist_count"); int nTotal = db_int(0, "PRAGMA localdb.page_count"); if( nFree>nTotal/4 ){ db_unprotect(PROTECT_ALL); db_multi_exec("VACUUM localdb;"); db_protect_pop(); } } if( g.db ){ int rc; sqlite3_wal_checkpoint(g.db, 0); rc = sqlite3_close(g.db); if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc); if( rc==SQLITE_BUSY && reportErrors ){ while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){ fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); } } g.db = 0; } g.repositoryOpen = 0; g.localOpen = 0; db.bProtectTriggers = 0; assert( g.dbConfig==0 ); assert( g.zConfigDbName==0 ); backoffice_run_if_needed(); } /* ** Close the database as quickly as possible without unnecessary processing. */ void db_panic_close(void){ if( g.db ){ int rc; sqlite3_wal_checkpoint(g.db, 0); rc = sqlite3_close(g.db); if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc); db_clear_authorizer(); } g.db = 0; g.repositoryOpen = 0; g.localOpen = 0; } /* |
︙ | ︙ | |||
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 | } if( zUser==0 ){ zUser = fossil_getenv("USERNAME"); } if( zUser==0 ){ zUser = "root"; } db_multi_exec( "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser ); db_multi_exec( "UPDATE user SET cap='s', pw=%Q" " WHERE login=%Q", fossil_random_password(10), zUser ); if( !setupUserOnly ){ db_multi_exec( "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('nobody','','gjorz','Nobody');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('developer','','ei','Dev');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('reader','','kptw','Reader');" ); } } /* ** Return a pointer to a string that contains the RHS of an IN operator ** that will select CONFIG table names that are in the list of control ** settings. */ | > > | 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 | } if( zUser==0 ){ zUser = fossil_getenv("USERNAME"); } if( zUser==0 ){ zUser = "root"; } db_unprotect(PROTECT_USER); db_multi_exec( "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser ); db_multi_exec( "UPDATE user SET cap='s', pw=%Q" " WHERE login=%Q", fossil_random_password(10), zUser ); if( !setupUserOnly ){ db_multi_exec( "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('nobody','','gjorz','Nobody');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('developer','','ei','Dev');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('reader','','kptw','Reader');" ); } db_protect_pop(); } /* ** Return a pointer to a string that contains the RHS of an IN operator ** that will select CONFIG table names that are in the list of control ** settings. */ |
︙ | ︙ | |||
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ const char *zDefaultUser /* Default user for the repository */ ){ char *zDate; Blob hash; Blob manifest; db_set("content-schema", CONTENT_SCHEMA, 0); db_set("aux-schema", AUX_SCHEMA_MAX, 0); db_set("rebuilt", get_version(), 0); db_set("admin-log", "1", 0); db_set("access-log", "1", 0); db_multi_exec( "INSERT INTO config(name,value,mtime)" | > | 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ const char *zDefaultUser /* Default user for the repository */ ){ char *zDate; Blob hash; Blob manifest; db_unprotect(PROTECT_ALL); db_set("content-schema", CONTENT_SCHEMA, 0); db_set("aux-schema", AUX_SCHEMA_MAX, 0); db_set("rebuilt", get_version(), 0); db_set("admin-log", "1", 0); db_set("access-log", "1", 0); db_multi_exec( "INSERT INTO config(name,value,mtime)" |
︙ | ︙ | |||
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 | " mtime = (SELECT u2.mtime FROM settingSrc.user u2" " WHERE u2.login = user.login)," " photo = (SELECT u2.photo FROM settingSrc.user u2" " WHERE u2.login = user.login)" " WHERE user.login IN ('anonymous','nobody','developer','reader');" ); } if( zInitialDate ){ int rid; blob_zero(&manifest); blob_appendf(&manifest, "C initial\\sempty\\scheck-in\n"); zDate = date_in_standard_format(zInitialDate); blob_appendf(&manifest, "D %s\n", zDate); | > | 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 | " mtime = (SELECT u2.mtime FROM settingSrc.user u2" " WHERE u2.login = user.login)," " photo = (SELECT u2.photo FROM settingSrc.user u2" " WHERE u2.login = user.login)" " WHERE user.login IN ('anonymous','nobody','developer','reader');" ); } db_protect_pop(); if( zInitialDate ){ int rid; blob_zero(&manifest); blob_appendf(&manifest, "C initial\\sempty\\scheck-in\n"); zDate = date_in_standard_format(zInitialDate); blob_appendf(&manifest, "D %s\n", zDate); |
︙ | ︙ | |||
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 | z = fossil_strdup(zDefault); }else if( zFormat!=0 ){ z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z); } return z; } void db_set(const char *zName, const char *zValue, int globalFlag){ db_begin_transaction(); if( globalFlag ){ db_swap_connections(); db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", zName, zValue); db_swap_connections(); }else{ db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", zName, zValue); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_end_transaction(0); } void db_unset(const char *zName, int globalFlag){ db_begin_transaction(); if( globalFlag ){ db_swap_connections(); db_multi_exec("DELETE FROM global_config WHERE name=%Q", zName); db_swap_connections(); }else{ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_end_transaction(0); } int db_is_global(const char *zName){ int rc = 0; if( g.zConfigDbName ){ db_swap_connections(); rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName); | > > > > > | 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 | z = fossil_strdup(zDefault); }else if( zFormat!=0 ){ z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z); } return z; } void db_set(const char *zName, const char *zValue, int globalFlag){ db_assert_protection_off_or_not_sensitive(zName); db_unprotect(PROTECT_CONFIG); db_begin_transaction(); if( globalFlag ){ db_swap_connections(); db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", zName, zValue); db_swap_connections(); }else{ db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", zName, zValue); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_end_transaction(0); db_protect_pop(); } void db_unset(const char *zName, int globalFlag){ db_begin_transaction(); db_unprotect(PROTECT_CONFIG); if( globalFlag ){ db_swap_connections(); db_multi_exec("DELETE FROM global_config WHERE name=%Q", zName); db_swap_connections(); }else{ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_protect_pop(); db_end_transaction(0); } int db_is_global(const char *zName){ int rc = 0; if( g.zConfigDbName ){ db_swap_connections(); rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName); |
︙ | ︙ | |||
2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 | db_swap_connections(); v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } return v; } void db_set_int(const char *zName, int value, int globalFlag){ if( globalFlag ){ db_swap_connections(); db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", zName, value); db_swap_connections(); }else{ db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%d,now())", zName, value); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } } int db_get_boolean(const char *zName, int dflt){ char *zVal = db_get(zName, dflt ? "on" : "off"); if( is_truth(zVal) ){ dflt = 1; }else if( is_false(zVal) ){ dflt = 0; | > > > | 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 | db_swap_connections(); v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } return v; } void db_set_int(const char *zName, int value, int globalFlag){ db_assert_protection_off_or_not_sensitive(zName); db_unprotect(PROTECT_CONFIG); if( globalFlag ){ db_swap_connections(); db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", zName, value); db_swap_connections(); }else{ db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%d,now())", zName, value); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_protect_pop(); } int db_get_boolean(const char *zName, int dflt){ char *zVal = db_get(zName, dflt ? "on" : "off"); if( is_truth(zVal) ){ dflt = 1; }else if( is_false(zVal) ){ dflt = 0; |
︙ | ︙ | |||
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 | if( !g.localOpen ) return; zName = db_repository_filename(); } file_canonical_name(zName, &full, 0); (void)filename_collation(); /* Initialize before connection swap */ db_swap_connections(); zRepoSetting = mprintf("repo:%q", blob_str(&full)); db_multi_exec( "DELETE FROM global_config WHERE name %s = %Q;", filename_collation(), zRepoSetting ); db_multi_exec( "INSERT OR IGNORE INTO global_config(name,value)" "VALUES(%Q,1);", zRepoSetting ); fossil_free(zRepoSetting); if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){ Blob localRoot; file_canonical_name(g.zLocalRoot, &localRoot, 1); zCkoutSetting = mprintf("ckout:%q", blob_str(&localRoot)); db_multi_exec( "DELETE FROM global_config WHERE name %s = %Q;", filename_collation(), zCkoutSetting ); db_multi_exec( "REPLACE INTO global_config(name, value)" "VALUES(%Q,%Q);", zCkoutSetting, blob_str(&full) ); db_swap_connections(); db_optional_sql("repository", "DELETE FROM config WHERE name %s = %Q;", filename_collation(), zCkoutSetting ); db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" "VALUES(%Q,1,now());", zCkoutSetting ); fossil_free(zCkoutSetting); blob_reset(&localRoot); }else{ db_swap_connections(); } blob_reset(&full); } | > > > > > | 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 | if( !g.localOpen ) return; zName = db_repository_filename(); } file_canonical_name(zName, &full, 0); (void)filename_collation(); /* Initialize before connection swap */ db_swap_connections(); zRepoSetting = mprintf("repo:%q", blob_str(&full)); db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM global_config WHERE name %s = %Q;", filename_collation(), zRepoSetting ); db_multi_exec( "INSERT OR IGNORE INTO global_config(name,value)" "VALUES(%Q,1);", zRepoSetting ); db_protect_pop(); fossil_free(zRepoSetting); if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){ Blob localRoot; file_canonical_name(g.zLocalRoot, &localRoot, 1); zCkoutSetting = mprintf("ckout:%q", blob_str(&localRoot)); db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM global_config WHERE name %s = %Q;", filename_collation(), zCkoutSetting ); db_multi_exec( "REPLACE INTO global_config(name, value)" "VALUES(%Q,%Q);", zCkoutSetting, blob_str(&full) ); db_swap_connections(); db_optional_sql("repository", "DELETE FROM config WHERE name %s = %Q;", filename_collation(), zCkoutSetting ); db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" "VALUES(%Q,1,now());", zCkoutSetting ); db_protect_pop(); fossil_free(zCkoutSetting); blob_reset(&localRoot); }else{ db_swap_connections(); } blob_reset(&full); } |
︙ | ︙ | |||
3129 3130 3131 3132 3133 3134 3135 | ** See also: [[close]], [[clone]] */ void cmd_open(void){ int emptyFlag; int keepFlag; int forceMissingFlag; int allowNested; | < | 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 | ** See also: [[close]], [[clone]] */ void cmd_open(void){ int emptyFlag; int keepFlag; int forceMissingFlag; int allowNested; int setmtimeFlag; /* --setmtime. Set mtimes on files */ int bForce = 0; /* --force. Open even if non-empty dir */ static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 }; const char *zWorkDir; /* --workdir value */ const char *zRepo = 0; /* Name of the repository file */ const char *zRepoDir = 0; /* --repodir value */ char *zPwd; /* Initial working directory */ |
︙ | ︙ | |||
3240 3241 3242 3243 3244 3245 3246 | if( g.argc==4 ){ g.zOpenRevision = g.argv[3]; }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){ g.zOpenRevision = db_get("main-branch", 0); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 | if( g.argc==4 ){ g.zOpenRevision = g.argv[3]; }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){ g.zOpenRevision = db_get("main-branch", 0); } } #if defined(_WIN32) || defined(__CYGWIN__) # define LOCALDB_NAME "./_FOSSIL_" #else # define LOCALDB_NAME "./.fslckout" #endif db_init_database(LOCALDB_NAME, zLocalSchema, zLocalSchemaVmerge, #ifdef FOSSIL_LOCAL_WAL "COMMIT; PRAGMA journal_mode=WAL; BEGIN;", #endif (char*)0); db_delete_on_failure(LOCALDB_NAME); db_open_local(0); db_lset("repository", zRepo); db_record_repository_filename(zRepo); db_set_checkout(0); azNewArgv[0] = g.argv[0]; g.argv = azNewArgv; if( !emptyFlag ){ g.argc = 3; |
︙ | ︙ | |||
3374 3375 3376 3377 3378 3379 3380 | */ struct Setting { const char *name; /* Name of the setting */ const char *var; /* Internal variable name used by db_set() */ int width; /* Width of display. 0 for boolean values and ** negative for values which should not appear ** on the /setup_settings page. */ | | | > < | | | | | | | > | | > | < | | | < < < | 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 | */ struct Setting { const char *name; /* Name of the setting */ const char *var; /* Internal variable name used by db_set() */ int width; /* Width of display. 0 for boolean values and ** negative for values which should not appear ** on the /setup_settings page. */ char versionable; /* Is this setting versionable? */ char forceTextArea; /* Force using a text area for display? */ char sensitive; /* True if this a security-sensitive setting */ const char *def; /* Default value */ }; #endif /* INTERFACE */ /* ** SETTING: access-log boolean default=off ** ** When the access-log setting is enabled, all login attempts (successful ** and unsuccessful) on the web interface are recorded in the "access" table ** of the repository. */ /* ** SETTING: admin-log boolean default=off ** ** When the admin-log setting is enabled, configuration changes are recorded ** in the "admin_log" table of the repository. */ /* ** SETTING: allow-symlinks boolean default=off sensitive ** ** When allow-symlinks is OFF, Fossil does not see symbolic links ** (a.k.a "symlinks") on disk as a separate class of object. Instead Fossil ** sees the object that the symlink points to. Fossil will only manage files ** and directories, not symlinks. When a symlink is added to a repository, ** the object that the symlink points to is added, not the symlink itself. ** ** When allow-symlinks is ON, Fossil sees symlinks on disk as a separate ** object class that is distinct from files and directories. When a symlink ** is added to a repository, Fossil stores the target filename. In other ** words, Fossil stores the symlink itself, not the object that the symlink ** points to. ** ** Symlinks are not cross-platform. They are not available on all ** operating systems and file systems. Hence the allow-symlinks setting is ** OFF by default, for portability. */ /* ** SETTING: auto-captcha boolean default=on variable=autocaptcha ** If enabled, the /login page provides a button that will automatically ** fill in the captcha password. This makes things easier for human users, ** at the expense of also making logins easier for malicious robots. */ /* |
︙ | ︙ | |||
3468 3469 3470 3471 3472 3473 3474 | ** Backoffice processing does things such as delivering ** email notifications. So if this setting is true, and if ** there is no cron job periodically running "fossil backoffice", ** email notifications and other work normally done by the ** backoffice will not occur. */ /* | | | 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 | ** Backoffice processing does things such as delivering ** email notifications. So if this setting is true, and if ** there is no cron job periodically running "fossil backoffice", ** email notifications and other work normally done by the ** backoffice will not occur. */ /* ** SETTING: backoffice-logfile width=40 sensitive ** If backoffice-logfile is not an empty string and is a valid ** filename, then a one-line message is appended to that file ** every time the backoffice runs. This can be used for debugging, ** to ensure that backoffice is running appropriately. */ /* ** SETTING: binary-glob width=40 versionable block-text |
︙ | ︙ | |||
3545 3546 3547 3548 3549 3550 3551 | ** The crnl-glob setting is a compatibility alias. */ /* ** SETTING: crnl-glob width=40 versionable block-text ** This is an alias for the crlf-glob setting. */ /* | | | | | 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 | ** The crnl-glob setting is a compatibility alias. */ /* ** SETTING: crnl-glob width=40 versionable block-text ** This is an alias for the crlf-glob setting. */ /* ** SETTING: default-perms width=16 default=u sensitive ** Permissions given automatically to new users. For more ** information on permissions see the Users page in Server ** Administration of the HTTP UI. */ /* ** SETTING: diff-binary boolean default=on ** If enabled, permit files that may be binary ** or that match the "binary-glob" setting to be used with ** external diff programs. If disabled, skip these files. */ /* ** SETTING: diff-command width=40 sensitive ** The value is an external command to run when performing a diff. ** If undefined, the internal text diff will be used. */ /* ** SETTING: dont-push boolean default=off ** If enabled, prevent this repository from pushing from client to ** server. This can be used as an extra precaution to prevent ** accidental pushes to a public server from a private clone. */ /* ** SETTING: dotfiles boolean versionable default=off ** If enabled, include --dotfiles option for all compatible commands. */ /* ** SETTING: editor width=32 sensitive ** The value is an external command that will launch the ** text editor command used for check-in comments. */ /* ** SETTING: empty-dirs width=40 versionable block-text ** The value is a comma or newline-separated list of pathnames. On ** update and checkout commands, if no file or directory |
︙ | ︙ | |||
3615 3616 3617 3618 3619 3620 3621 | ** A comma- or newline-separated list of globs of filenames ** which are allowed to be edited using the /fileedit page. ** An empty list prohibits editing via that page. Note that ** it cannot edit binary files, so the list should not ** contain any globs for, e.g., images or PDFs. */ /* | | | | 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 | ** A comma- or newline-separated list of globs of filenames ** which are allowed to be edited using the /fileedit page. ** An empty list prohibits editing via that page. Note that ** it cannot edit binary files, so the list should not ** contain any globs for, e.g., images or PDFs. */ /* ** SETTING: gdiff-command width=40 default=gdiff sensitive ** The value is an external command to run when performing a graphical ** diff. If undefined, text diff will be used. */ /* ** SETTING: gmerge-command width=40 sensitive ** The value is a graphical merge conflict resolver command operating ** on four files. Examples: ** ** kdiff3 "%baseline" "%original" "%merge" -o "%output" ** xxdiff "%original" "%baseline" "%merge" -M "%output" ** meld "%baseline" "%original" "%merge" "%output" */ |
︙ | ︙ | |||
3755 3756 3757 3758 3759 3760 3761 | ** SETTING: mv-rm-files boolean default=off ** If enabled, the "mv" and "rename" commands will also move ** the associated files within the checkout -AND- the "rm" ** and "delete" commands will also remove the associated ** files from within the checkout. */ /* | | | 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 | ** SETTING: mv-rm-files boolean default=off ** If enabled, the "mv" and "rename" commands will also move ** the associated files within the checkout -AND- the "rm" ** and "delete" commands will also remove the associated ** files from within the checkout. */ /* ** SETTING: pgp-command width=40 sensitive ** Command used to clear-sign manifests at check-in. ** Default value is "gpg --clearsign -o" */ /* ** SETTING: forbid-delta-manifests boolean default=off ** If enabled on a client, new delta manifests are prohibited on ** commits. If enabled on a server, whenever a client attempts |
︙ | ︙ | |||
3815 3816 3817 3818 3819 3820 3821 | ** have a non-zero "repolist-skin" setting then the repository list is ** displayed using unadorned HTML ("skinless"). ** ** If repolist-skin has a value of 2, then the repository is omitted from ** the list in use cases 1 through 4, but not for 5 and 6. */ /* | | | | | | | | | | 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 | ** have a non-zero "repolist-skin" setting then the repository list is ** displayed using unadorned HTML ("skinless"). ** ** If repolist-skin has a value of 2, then the repository is omitted from ** the list in use cases 1 through 4, but not for 5 and 6. */ /* ** SETTING: self-register boolean default=off sensitive ** Allow users to register themselves through the HTTP UI. ** This is useful if you want to see other names than ** "Anonymous" in e.g. ticketing system. On the other hand ** users can not be deleted. */ /* ** SETTING: ssh-command width=40 sensitive ** The command used to talk to a remote machine with the "ssh://" protocol. */ /* ** SETTING: ssl-ca-location width=40 sensitive ** The full pathname to a file containing PEM encoded ** CA root certificates, or a directory of certificates ** with filenames formed from the certificate hashes as ** required by OpenSSL. ** ** If set, this will override the OS default list of ** OpenSSL CAs. If unset, the default list will be used. ** Some platforms may add additional certificates. ** Checking your platform behaviour is required if the ** exact contents of the CA root is critical for your ** application. */ /* ** SETTING: ssl-identity width=40 sensitive ** The full pathname to a file containing a certificate ** and private key in PEM format. Create by concatenating ** the certificate and private key files. ** ** This identity will be presented to SSL servers to ** authenticate this client, in addition to the normal ** password authentication. */ #ifdef FOSSIL_ENABLE_TCL /* ** SETTING: tcl boolean default=off sensitive ** If enabled Tcl integration commands will be added to the TH1 ** interpreter, allowing arbitrary Tcl expressions and ** scripts to be evaluated from TH1. Additionally, the Tcl ** interpreter will be able to evaluate arbitrary TH1 ** expressions and scripts. */ /* ** SETTING: tcl-setup width=40 block-text sensitive ** This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. */ #endif /* FOSSIL_ENABLE_TCL */ /* ** SETTING: tclsh width=80 default=tclsh sensitive ** Name of the external TCL interpreter used for such things ** as running the GUI diff viewer launched by the --tk option ** of the various "diff" commands. */ #ifdef FOSSIL_ENABLE_TH1_DOCS /* ** SETTING: th1-docs boolean default=off sensitive ** If enabled, this allows embedded documentation files to contain ** arbitrary TH1 scripts that are evaluated on the server. If native ** Tcl integration is also enabled, this setting has the ** potential to allow anybody with check-in privileges to ** do almost anything that the associated operating system ** user account could do. Extreme caution should be used ** when enabling this setting. |
︙ | ︙ | |||
3930 3931 3932 3933 3934 3935 3936 | ** SETTING: uv-sync boolean default=off ** If true, automatically send unversioned files as part ** of a "fossil clone" or "fossil sync" command. The ** default is false, in which case the -u option is ** needed to clone or sync unversioned files. */ /* | | | 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 | ** SETTING: uv-sync boolean default=off ** If true, automatically send unversioned files as part ** of a "fossil clone" or "fossil sync" command. The ** default is false, in which case the -u option is ** needed to clone or sync unversioned files. */ /* ** SETTING: web-browser width=30 sensitive ** A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. */ /* |
︙ | ︙ | |||
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 | } if( globalFlag && isManifest ){ fossil_fatal("cannot set 'manifest' globally"); } if( unsetFlag ){ db_unset(pSetting->name, globalFlag); }else{ db_set(pSetting->name, g.argv[3], globalFlag); } if( isManifest && g.localOpen ){ manifest_to_disk(db_lget_int("checkout", 0)); } }else{ while( pSetting->name ){ if( exactFlag ){ | > > | 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 | } if( globalFlag && isManifest ){ fossil_fatal("cannot set 'manifest' globally"); } if( unsetFlag ){ db_unset(pSetting->name, globalFlag); }else{ db_protect_only(PROTECT_NONE); db_set(pSetting->name, g.argv[3], globalFlag); db_protect_pop(); } if( isManifest && g.localOpen ){ manifest_to_disk(db_lget_int("checkout", 0)); } }else{ while( pSetting->name ){ if( exactFlag ){ |
︙ | ︙ |
Changes to src/file.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | ** ** The difference is in the handling of symbolic links. RepoFILE should be ** used for files that are under management by a Fossil repository. ExtFILE ** should be used for files that are not under management. SymFILE is for ** a few special cases such as the "fossil test-tarball" command when we never ** want to follow symlinks. ** | < < | | > < | | | > | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | ** ** The difference is in the handling of symbolic links. RepoFILE should be ** used for files that are under management by a Fossil repository. ExtFILE ** should be used for files that are not under management. SymFILE is for ** a few special cases such as the "fossil test-tarball" command when we never ** want to follow symlinks. ** ** ExtFILE Symbolic links always refer to the object to which the ** link points. Symlinks are never recognized as symlinks but ** instead always appear to the the target object. ** ** SymFILE Symbolic links always appear to be files whose name is ** the target pathname of the symbolic link. ** ** RepoFILE Like symfile is allow-symlinks is true, or like ** ExtFile if allow-symlinks is false. In other words, ** symbolic links are only recognized as something different ** from files or directories if allow-symlinks is true. */ #define ExtFILE 0 /* Always follow symlinks */ #define RepoFILE 1 /* Follow symlinks if and only if allow-symlinks is OFF */ #define SymFILE 2 /* Never follow symlinks */ #include <dirent.h> #if defined(_WIN32) |
︙ | ︙ | |||
132 133 134 135 136 137 138 | const char *zFilename, /* name of file or directory to inspect. */ struct fossilStat *buf, /* pointer to buffer where info should go. */ int eFType /* Look at symlink itself if RepoFILE and enabled. */ ){ int rc; void *zMbcs = fossil_utf8_to_path(zFilename, 0); #if !defined(_WIN32) | | > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | const char *zFilename, /* name of file or directory to inspect. */ struct fossilStat *buf, /* pointer to buffer where info should go. */ int eFType /* Look at symlink itself if RepoFILE and enabled. */ ){ int rc; void *zMbcs = fossil_utf8_to_path(zFilename, 0); #if !defined(_WIN32) if( (eFType=RepoFILE && db_allow_symlinks()) || eFType==SymFILE ){ /* Symlinks look like files whose content is the name of the target */ rc = lstat(zMbcs, buf); }else{ /* Symlinks look like the object to which they point */ rc = stat(zMbcs, buf); } #else rc = win32_stat(zMbcs, buf, eFType); #endif fossil_path_free(zMbcs); return rc; |
︙ | ︙ | |||
314 315 316 317 318 319 320 | return file_perm(zFilename, eFType)==PERM_EXE; } /* ** Return TRUE if the named file is a symlink and symlinks are allowed. ** Return false for all other cases. ** | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | return file_perm(zFilename, eFType)==PERM_EXE; } /* ** Return TRUE if the named file is a symlink and symlinks are allowed. ** Return false for all other cases. ** ** This routines assumes RepoFILE - that zFilename is always a file ** under management. ** ** On Windows, always return False. */ int file_islink(const char *zFilename){ return file_perm(zFilename, RepoFILE)==PERM_LNK; } /* ** Check every sub-directory of zRoot along the path to zFile. ** If any sub-directory is really an ordinary file or a symbolic link, ** return an integer which is the length of the prefix of zFile which ** is the name of that object. Return 0 if all no non-directory ** objects are found along the path. ** ** Example: Given inputs ** ** zRoot = /home/alice/project1 ** zFile = /home/alice/project1/main/src/js/fileA.js ** ** Look for objects in the following order: ** ** /home/alice/project/main ** /home/alice/project/main/src ** /home/alice/project/main/src/js ** ** If any of those objects exist and are something other than a directory ** then return the length of the name of the first non-directory object ** seen. */ int file_nondir_objects_on_path(const char *zRoot, const char *zFile){ int i = (int)strlen(zRoot); char *z = fossil_strdup(zFile); assert( fossil_strnicmp(zRoot, z, i)==0 ); if( i && zRoot[i-1]=='/' ) i--; while( z[i]=='/' ){ int j, rc; for(j=i+1; z[j] && z[j]!='/'; j++){} if( z[j]!='/' ) break; z[j] = 0; rc = file_isdir(z, SymFILE); if( rc!=1 ){ if( rc==2 ){ fossil_free(z); return j; } break; } z[j] = '/'; i = j; } fossil_free(z); return 0; } /* ** The file named zFile is suppose to be an in-tree file. Check to ** ensure that it will be safe to write to this file by verifying that ** there are no symlinks or other non-directory objects in between the ** root of the checkout and zFile. ** ** If a problem is found, print a warning message (using fossil_warning()) ** and return non-zero. If everything is ok, return zero. */ int file_unsafe_in_tree_path(const char *zFile){ int n; if( !file_is_absolute_path(zFile) ){ fossil_panic("%s is not an absolute pathname",zFile); } if( fossil_strnicmp(g.zLocalRoot, zFile, (int)strlen(g.zLocalRoot)) ){ fossil_panic("%s is not a prefix of %s", g.zLocalRoot, zFile); } n = file_nondir_objects_on_path(g.zLocalRoot, zFile); if( n ){ fossil_warning("cannot write to %s because non-directory object %.*s" " is in the way", zFile, n, zFile); } return n; } /* ** Return 1 if zFilename is a directory. Return 0 if zFilename ** does not exist. Return 2 if zFilename exists but is something ** other than a directory. */ int file_isdir(const char *zFilename, int eFType){ |
︙ | ︙ | |||
568 569 570 571 572 573 574 | ** zFilename is a symbolic link, it is the object that zFilename points ** to that is modified. */ int file_setexe(const char *zFilename, int onoff){ int rc = 0; #if !defined(_WIN32) struct stat buf; | | > > > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | ** zFilename is a symbolic link, it is the object that zFilename points ** to that is modified. */ int file_setexe(const char *zFilename, int onoff){ int rc = 0; #if !defined(_WIN32) struct stat buf; if( fossil_stat(zFilename, &buf, RepoFILE)!=0 || S_ISLNK(buf.st_mode) || S_ISDIR(buf.st_mode) ){ return 0; } if( onoff ){ int targetMode = (buf.st_mode & 0444)>>2; if( (buf.st_mode & 0100)==0 ){ chmod(zFilename, buf.st_mode | targetMode); rc = 1; |
︙ | ︙ | |||
1234 1235 1236 1237 1238 1239 1240 | Blob x; int rc; sqlite3_int64 iMtime; struct fossilStat testFileStat; memset(zBuf, 0, sizeof(zBuf)); blob_zero(&x); file_canonical_name(zPath, &x, slash); | > | < | 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 | Blob x; int rc; sqlite3_int64 iMtime; struct fossilStat testFileStat; memset(zBuf, 0, sizeof(zBuf)); blob_zero(&x); file_canonical_name(zPath, &x, slash); char *zFull = blob_str(&x); fossil_print("[%s] -> [%s]\n", zPath, zFull); memset(&testFileStat, 0, sizeof(struct fossilStat)); rc = fossil_stat(zPath, &testFileStat, 0); fossil_print(" stat_rc = %d\n", rc); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size); fossil_print(" stat_size = %s\n", zBuf); if( g.db==0 ) sqlite3_open(":memory:", &g.db); z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime); |
︙ | ︙ | |||
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | fossil_print(" file_mode(RepoFILE) = 0%o\n", file_mode(zPath,RepoFILE)); fossil_print(" file_isfile(RepoFILE) = %d\n", file_isfile(zPath,RepoFILE)); fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zPath)); fossil_print(" file_islink = %d\n", file_islink(zPath)); fossil_print(" file_isexe(RepoFILE) = %d\n", file_isexe(zPath,RepoFILE)); fossil_print(" file_isdir(RepoFILE) = %d\n", file_isdir(zPath,RepoFILE)); fossil_print(" file_is_repository = %d\n", file_is_repository(zPath)); if( reset ) resetStat(); } /* ** COMMAND: test-file-environment ** ** Usage: %fossil test-file-environment FILENAME... ** ** Display the effective file handling subsystem "settings" and then ** display file system information about the files specified, if any. ** ** Options: ** ** --allow-symlinks BOOLEAN Temporarily turn allow-symlinks on/off ** --open-config Open the configuration database first. | > > > < > > > < < > > > > > > > > > > > > > | 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 | fossil_print(" file_mode(RepoFILE) = 0%o\n", file_mode(zPath,RepoFILE)); fossil_print(" file_isfile(RepoFILE) = %d\n", file_isfile(zPath,RepoFILE)); fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zPath)); fossil_print(" file_islink = %d\n", file_islink(zPath)); fossil_print(" file_isexe(RepoFILE) = %d\n", file_isexe(zPath,RepoFILE)); fossil_print(" file_isdir(RepoFILE) = %d\n", file_isdir(zPath,RepoFILE)); fossil_print(" file_is_repository = %d\n", file_is_repository(zPath)); fossil_print(" file_is_reserved_name = %d\n", file_is_reserved_name(zFull,-1)); blob_reset(&x); if( reset ) resetStat(); } /* ** COMMAND: test-file-environment ** ** Usage: %fossil test-file-environment FILENAME... ** ** Display the effective file handling subsystem "settings" and then ** display file system information about the files specified, if any. ** ** Options: ** ** --allow-symlinks BOOLEAN Temporarily turn allow-symlinks on/off ** --open-config Open the configuration database first. ** --reset Reset cached stat() info for each file. ** --root ROOT Use ROOT as the root of the checkout ** --slash Trailing slashes, if any, are retained. */ void cmd_test_file_environment(void){ int i; int slashFlag = find_option("slash",0,0)!=0; int resetFlag = find_option("reset",0,0)!=0; const char *zRoot = find_option("root",0,1); const char *zAllow = find_option("allow-symlinks",0,1); if( find_option("open-config", 0, 0)!=0 ){ Th_OpenConfig(1); } db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); fossil_print("filenames_are_case_sensitive() = %d\n", filenames_are_case_sensitive()); if( zAllow ){ g.allowSymlinks = !is_false(zAllow); } if( zRoot==0 ) zRoot = g.zLocalRoot; fossil_print("db_allow_symlinks() = %d\n", db_allow_symlinks()); fossil_print("local-root = [%s]\n", zRoot); for(i=2; i<g.argc; i++){ char *z; emitFileStat(g.argv[i], slashFlag, resetFlag); z = file_canonical_name_dup(g.argv[i]); fossil_print(" file_canonical_name = %s\n", z); fossil_print(" file_nondir_path = "); if( fossil_strnicmp(zRoot,z,(int)strlen(zRoot))!=0 ){ fossil_print("(--root is not a prefix of this file)\n"); }else{ int n = file_nondir_objects_on_path(zRoot, z); fossil_print("%.*s\n", n, z); } fossil_free(z); } } /* ** COMMAND: test-canonical-name ** ** Usage: %fossil test-canonical-name FILENAME... |
︙ | ︙ | |||
2406 2407 2408 2409 2410 2411 2412 | ** special case, if it ends with a period then a pointer to the ** terminating NUL byte is returned. */ const char * file_extension(const char *zFileName){ const char * zExt = zFileName ? strrchr(zFileName, '.') : 0; return zExt ? &zExt[1] : 0; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 | ** special case, if it ends with a period then a pointer to the ** terminating NUL byte is returned. */ const char * file_extension(const char *zFileName){ const char * zExt = zFileName ? strrchr(zFileName, '.') : 0; return zExt ? &zExt[1] : 0; } /* ** Returns non-zero if the specified file name ends with any reserved name, ** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match ** or 2 for a tail match on a longer file name. ** ** For the sake of efficiency, zFilename must be a canonical name, e.g. an ** absolute path using only forward slash ('/') as a directory separator. ** ** nFilename must be the length of zFilename. When negative, strlen() will ** be used to calculate it. */ int file_is_reserved_name(const char *zFilename, int nFilename){ const char *zEnd; /* one-after-the-end of zFilename */ int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */ assert( zFilename && "API misuse" ); if( nFilename<0 ) nFilename = (int)strlen(zFilename); if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */ zEnd = zFilename + nFilename; if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */ /* Check for (-wal, -shm, -journal) suffixes, with an eye towards ** runtime speed. */ if( zEnd[-4]=='-' ){ if( fossil_strnicmp("wal", &zEnd[-3], 3) && fossil_strnicmp("shm", &zEnd[-3], 3) ){ return 0; } gotSuffix = 4; }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */ if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0; gotSuffix = 8; } if( gotSuffix ){ assert( 4==gotSuffix || 8==gotSuffix ); zEnd -= gotSuffix; nFilename -= gotSuffix; gotSuffix = 1; } assert( nFilename>=8 && "strlen(_FOSSIL_)" ); assert( gotSuffix==0 || gotSuffix==1 ); } switch( zEnd[-1] ){ case '_':{ if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0; if( 8==nFilename ) return 1; return zEnd[-9]=='/' ? 2 : gotSuffix; } case 'T': case 't':{ if( nFilename<9 || zEnd[-9]!='.' || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){ return 0; } if( 9==nFilename ) return 1; return zEnd[-10]=='/' ? 2 : gotSuffix; } default:{ return 0; } } } |
Changes to src/forum.c.
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | if( P("approve") ){ const char *zUserToTrust; moderation_approve('f', fpid); if( g.perm.AdminForum && PB("trust") && (zUserToTrust = P("trustuser"))!=0 ){ db_multi_exec("UPDATE user SET cap=cap||'4' " "WHERE login=%Q AND cap NOT GLOB '*4*'", zUserToTrust); } cgi_redirectf("%R/forumpost/%S",P("fpid")); return; } if( P("reject") ){ char *zParent = db_text(0, | > > | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 | if( P("approve") ){ const char *zUserToTrust; moderation_approve('f', fpid); if( g.perm.AdminForum && PB("trust") && (zUserToTrust = P("trustuser"))!=0 ){ db_unprotect(PROTECT_USER); db_multi_exec("UPDATE user SET cap=cap||'4' " "WHERE login=%Q AND cap NOT GLOB '*4*'", zUserToTrust); db_protect_pop(); } cgi_redirectf("%R/forumpost/%S",P("fpid")); return; } if( P("reject") ){ char *zParent = db_text(0, |
︙ | ︙ |
Changes to src/hook.c.
︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | ** probably be deferred until after the new artifacts arrive. ** ** If N==0, then there is no expectation of new artifacts arriving ** soon and so post-receive hooks can be run without delay. */ void hook_expecting_more_artifacts(int N){ if( N>0 ){ db_multi_exec( "REPLACE INTO config(name,value,mtime)" "VALUES('hook-embargo',now()+%d,now())", N ); }else{ db_unset("hook-embargo",0); } } /* | > > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | ** probably be deferred until after the new artifacts arrive. ** ** If N==0, then there is no expectation of new artifacts arriving ** soon and so post-receive hooks can be run without delay. */ void hook_expecting_more_artifacts(int N){ if( N>0 ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name,value,mtime)" "VALUES('hook-embargo',now()+%d,now())", N ); db_protect_pop(); }else{ db_unset("hook-embargo",0); } } /* |
︙ | ︙ | |||
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | verify_all_options(); if( zCmd==0 || zType==0 ){ fossil_fatal("the --command and --type options are required"); } validate_type(zType); nSeq = zSeq ? atoi(zSeq) : 10; db_begin_write(); db_multi_exec( "INSERT OR IGNORE INTO config(name,value) VALUES('hooks','[]');\n" "UPDATE config" " SET value=json_insert(" " CASE WHEN json_valid(value) THEN value ELSE '[]' END,'$[#]'," " json_object('cmd',%Q,'type',%Q,'seq',%d))," " mtime=now()" " WHERE name='hooks';", zCmd, zType, nSeq ); db_commit_transaction(); }else if( strncmp(zCmd, "edit", nCmd)==0 ){ const char *zCmd = find_option("command",0,1); const char *zType = find_option("type",0,1); const char *zSeq = find_option("sequence",0,1); int nSeq; | > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | verify_all_options(); if( zCmd==0 || zType==0 ){ fossil_fatal("the --command and --type options are required"); } validate_type(zType); nSeq = zSeq ? atoi(zSeq) : 10; db_begin_write(); db_unprotect(PROTECT_CONFIG); db_multi_exec( "INSERT OR IGNORE INTO config(name,value) VALUES('hooks','[]');\n" "UPDATE config" " SET value=json_insert(" " CASE WHEN json_valid(value) THEN value ELSE '[]' END,'$[#]'," " json_object('cmd',%Q,'type',%Q,'seq',%d))," " mtime=now()" " WHERE name='hooks';", zCmd, zType, nSeq ); db_protect_pop(); db_commit_transaction(); }else if( strncmp(zCmd, "edit", nCmd)==0 ){ const char *zCmd = find_option("command",0,1); const char *zType = find_option("type",0,1); const char *zSeq = find_option("sequence",0,1); int nSeq; |
︙ | ︙ | |||
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | if( zType ){ blob_append_sql(&sql, ",'$[%d].type',%Q", id, zType); } if( zSeq ){ blob_append_sql(&sql, ",'$[%d].seq',%d", id, nSeq); } blob_append_sql(&sql,") WHERE name='hooks';"); db_multi_exec("%s", blob_sql_text(&sql)); blob_reset(&sql); } db_commit_transaction(); }else if( strncmp(zCmd, "delete", nCmd)==0 ){ int i; verify_all_options(); if( g.argc<4 ) usage("delete ID ..."); db_begin_write(); db_multi_exec( "INSERT OR IGNORE INTO config(name,value) VALUES('hooks','[]');\n" ); for(i=3; i<g.argc; i++){ const char *zId = g.argv[i]; if( strcmp(zId,"all")==0 ){ db_set("hooks","[]", 0); | > > > | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | if( zType ){ blob_append_sql(&sql, ",'$[%d].type',%Q", id, zType); } if( zSeq ){ blob_append_sql(&sql, ",'$[%d].seq',%d", id, nSeq); } blob_append_sql(&sql,") WHERE name='hooks';"); db_unprotect(PROTECT_CONFIG); db_multi_exec("%s", blob_sql_text(&sql)); db_protect_pop(); blob_reset(&sql); } db_commit_transaction(); }else if( strncmp(zCmd, "delete", nCmd)==0 ){ int i; verify_all_options(); if( g.argc<4 ) usage("delete ID ..."); db_begin_write(); db_unprotect(PROTECT_CONFIG); db_multi_exec( "INSERT OR IGNORE INTO config(name,value) VALUES('hooks','[]');\n" ); for(i=3; i<g.argc; i++){ const char *zId = g.argv[i]; if( strcmp(zId,"all")==0 ){ db_set("hooks","[]", 0); |
︙ | ︙ | |||
319 320 321 322 323 324 325 326 327 328 329 330 331 332 | " SET value=json_remove(" " CASE WHEN json_valid(value) THEN value ELSE '[]' END,'$[%d]')," " mtime=now()" " WHERE name='hooks';", atoi(zId) ); } db_commit_transaction(); }else if( strncmp(zCmd, "list", nCmd)==0 ){ Stmt q; int n = 0; verify_all_options(); db_prepare(&q, | > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | " SET value=json_remove(" " CASE WHEN json_valid(value) THEN value ELSE '[]' END,'$[%d]')," " mtime=now()" " WHERE name='hooks';", atoi(zId) ); } db_protect_pop(); db_commit_transaction(); }else if( strncmp(zCmd, "list", nCmd)==0 ){ Stmt q; int n = 0; verify_all_options(); db_prepare(&q, |
︙ | ︙ |
Changes to src/http.c.
︙ | ︙ | |||
373 374 375 376 377 378 379 380 381 382 383 384 385 | j = strlen(zLine) - 1; while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ j -= 4; zLine[j] = 0; } if( (mHttpFlags & HTTP_QUIET)==0 ){ fossil_print("redirect with status %d to %s\n", rc, &zLine[i]); } wasHttps = g.url.isHttps; url_parse(&zLine[i], 0); if( wasHttps && !g.url.isHttps ){ fossil_warning("cannot redirect from HTTPS to HTTP"); goto write_err; | > > > > > | > > > > | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | j = strlen(zLine) - 1; while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ j -= 4; zLine[j] = 0; } if( (mHttpFlags & HTTP_QUIET)==0 ){ fossil_print("redirect with status %d to %s\n", rc, &zLine[i]); } if( g.url.isFile || g.url.isSsh ){ fossil_warning("cannot redirect from %s to %s", g.url.canonical, &zLine[i]); goto write_err; } wasHttps = g.url.isHttps; url_parse(&zLine[i], 0); if( wasHttps && !g.url.isHttps ){ fossil_warning("cannot redirect from HTTPS to HTTP"); goto write_err; } if( g.url.isSsh || g.url.isFile ){ fossil_warning("cannot redirect to %s", &zLine[i]); goto write_err; } transport_close(&g.url); transport_global_shutdown(&g.url); fSeenHttpAuth = 0; if( g.zHttpAuth ) free(g.zHttpAuth); g.zHttpAuth = get_httpauth(); if( rc==301 || rc==308 ) url_remember(); return http_exchange(pSend, pReply, mHttpFlags, |
︙ | ︙ |
Changes to src/http_ssl.c.
︙ | ︙ | |||
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 | if( strncmp("remove-exception",zCmd,nCmd)==0 ){ int i; Blob sql; char *zSep = "("; db_begin_transaction(); blob_init(&sql, 0, 0); if( g.argc==4 && find_option("all",0,0)!=0 ){ blob_append_sql(&sql, "DELETE FROM global_config WHERE name GLOB 'cert:*';\n" "DELETE FROM global_config WHERE name GLOB 'trusted:*';\n" "DELETE FROM config WHERE name GLOB 'cert:*';\n" "DELETE FROM config WHERE name GLOB 'trusted:*';\n" ); }else{ if( g.argc<4 ){ usage("remove-exception DOMAIN-NAME ..."); } blob_append_sql(&sql,"DELETE FROM global_config WHERE name IN "); for(i=3; i<g.argc; i++){ blob_append_sql(&sql,"%s'cert:%q','trust:%q'", | > > | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 | if( strncmp("remove-exception",zCmd,nCmd)==0 ){ int i; Blob sql; char *zSep = "("; db_begin_transaction(); blob_init(&sql, 0, 0); if( g.argc==4 && find_option("all",0,0)!=0 ){ db_unprotect(PROTECT_CONFIG); blob_append_sql(&sql, "DELETE FROM global_config WHERE name GLOB 'cert:*';\n" "DELETE FROM global_config WHERE name GLOB 'trusted:*';\n" "DELETE FROM config WHERE name GLOB 'cert:*';\n" "DELETE FROM config WHERE name GLOB 'trusted:*';\n" ); db_protect_pop(); }else{ if( g.argc<4 ){ usage("remove-exception DOMAIN-NAME ..."); } blob_append_sql(&sql,"DELETE FROM global_config WHERE name IN "); for(i=3; i<g.argc; i++){ blob_append_sql(&sql,"%s'cert:%q','trust:%q'", |
︙ | ︙ |
Changes to src/import.c.
︙ | ︙ | |||
1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 | } if( !incrFlag ){ if( forceFlag ) file_delete(g.argv[2]); db_create_repository(g.argv[2]); } db_open_repository(g.argv[2]); db_open_config(0, 0); db_begin_transaction(); if( !incrFlag ){ db_initial_setup(0, 0, zDefaultUser); db_set("main-branch", gimport.zTrunkName, 0); } | > | 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 | } if( !incrFlag ){ if( forceFlag ) file_delete(g.argv[2]); db_create_repository(g.argv[2]); } db_open_repository(g.argv[2]); db_open_config(0, 0); db_unprotect(PROTECT_ALL); db_begin_transaction(); if( !incrFlag ){ db_initial_setup(0, 0, zDefaultUser); db_set("main-branch", gimport.zTrunkName, 0); } |
︙ | ︙ |
Changes to src/interwiki.c.
︙ | ︙ | |||
190 191 192 193 194 195 196 | const char *zName; const char *zBase = find_option("base",0,1); const char *zHash = find_option("hash",0,1); const char *zWiki = find_option("wiki",0,1); verify_all_options(); if( g.argc!=4 ) usage("add TAG ?OPTIONS?"); zName = g.argv[3]; | | > > > > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | const char *zName; const char *zBase = find_option("base",0,1); const char *zHash = find_option("hash",0,1); const char *zWiki = find_option("wiki",0,1); verify_all_options(); if( g.argc!=4 ) usage("add TAG ?OPTIONS?"); zName = g.argv[3]; if( zBase==0 ){ fossil_fatal("the --base option is required"); } if( !interwiki_valid_name(zName) ){ fossil_fatal("not a valid interwiki tag: \"%s\"", zName); } db_begin_write(); db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('interwiki:'||lower(%Q)," " json_object('base',%Q,'hash',%Q,'wiki',%Q)," " now());", zName, zBase, zHash, zWiki ); setup_incr_cfgcnt(); db_protect_pop(); db_commit_transaction(); }else if( strncmp(zCmd, "delete", nCmd)==0 ){ int i; verify_all_options(); if( g.argc<4 ) usage("delete ID ..."); db_begin_write(); db_unprotect(PROTECT_CONFIG); for(i=3; i<g.argc; i++){ const char *zName = g.argv[i]; db_multi_exec( "DELETE FROM config WHERE name='interwiki:%q'", zName ); } setup_incr_cfgcnt(); db_protect_pop(); db_commit_transaction(); }else if( strncmp(zCmd, "list", nCmd)==0 ){ Stmt q; int n = 0; verify_all_options(); db_prepare(&q, |
︙ | ︙ | |||
314 315 316 317 318 319 320 | } if( P("submit")!=0 && cgi_csrf_safe(1) ){ zTag = PT("tag"); zBase = PT("base"); zHash = PT("hash"); zWiki = PT("wiki"); if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){ | | > > > > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | } if( P("submit")!=0 && cgi_csrf_safe(1) ){ zTag = PT("tag"); zBase = PT("base"); zHash = PT("hash"); zWiki = PT("wiki"); if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){ zErr = mprintf("Not a valid interwiki tag name: \"%s\"", zTag?zTag : ""); }else if( zBase==0 || zBase[0]==0 ){ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name='interwiki:%q';", zTag); db_protect_pop(); }else{ if( zHash && zHash[0]==0 ) zHash = 0; if( zWiki && zWiki[0]==0 ) zWiki = 0; db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name,value,mtime)" "VALUES('interwiki:'||lower(%Q)," " json_object('base',%Q,'hash',%Q,'wiki',%Q)," " now());", zTag, zBase, zHash, zWiki); db_protect_pop(); } } style_header("Interwiki Map Configuration"); @ <p>Interwiki links are hyperlink targets of the form @ <blockquote><i>Tag</i><b>:</b><i>PageName</i></blockquote> @ <p>Such links resolve to links to <i>PageName</i> on a separate server |
︙ | ︙ |
Changes to src/json_config.c.
︙ | ︙ | |||
81 82 83 84 85 86 87 | { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, | < | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, { "ticket-change", CONFIGSET_TKT }, { "ticket-newpage", CONFIGSET_TKT }, { "ticket-viewpage", CONFIGSET_TKT }, |
︙ | ︙ |
Changes to src/json_user.c.
︙ | ︙ | |||
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | goto error; }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, "User %s already exists.", zName); goto error; }else{ Stmt ins = empty_Stmt; db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName); db_step( &ins ); db_finalize(&ins); uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); assert(uid>0); zNameNew = zName; cson_object_set( pUser, "uid", cson_value_new_integer(uid) ); } }else{ uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); | > > | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | goto error; }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, "User %s already exists.", zName); goto error; }else{ Stmt ins = empty_Stmt; db_unprotect(PROTECT_USER); db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName); db_step( &ins ); db_finalize(&ins); db_protect_pop(); uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); assert(uid>0); zNameNew = zName; cson_object_set( pUser, "uid", cson_value_new_integer(uid) ); } }else{ uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); |
︙ | ︙ | |||
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | #else /* need name for login group support :/ */ blob_append_sql(&sql, " WHERE login=%Q", zName); #endif #if 0 puts(blob_str(&sql)); cson_output_FILE( cson_object_value(pUser), stdout, NULL ); #endif db_prepare(&q, "%s", blob_sql_text(&sql)); db_exec(&q); db_finalize(&q); #if TRY_LOGIN_GROUP if( zPW || cson_value_get_bool(forceLogout) ){ Blob groupSql = empty_blob; char * zErr = NULL; blob_append_sql(&groupSql, "INSERT INTO user(login)" " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);", zName, zName ); blob_append(&groupSql, blob_str(&sql), blob_size(&sql)); login_group_sql(blob_str(&groupSql), NULL, NULL, &zErr); blob_reset(&groupSql); if( zErr ){ json_set_err( FSL_JSON_E_UNKNOWN, "Repo-group update at least partially failed: %s", zErr); free(zErr); goto error; | > > > > | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | #else /* need name for login group support :/ */ blob_append_sql(&sql, " WHERE login=%Q", zName); #endif #if 0 puts(blob_str(&sql)); cson_output_FILE( cson_object_value(pUser), stdout, NULL ); #endif db_unprotect(PROTECT_USER); db_prepare(&q, "%s", blob_sql_text(&sql)); db_exec(&q); db_finalize(&q); db_protect_pop(); #if TRY_LOGIN_GROUP if( zPW || cson_value_get_bool(forceLogout) ){ Blob groupSql = empty_blob; char * zErr = NULL; blob_append_sql(&groupSql, "INSERT INTO user(login)" " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);", zName, zName ); blob_append(&groupSql, blob_str(&sql), blob_size(&sql)); db_unprotect(PROTECT_USER); login_group_sql(blob_str(&groupSql), NULL, NULL, &zErr); db_protect_pop(); blob_reset(&groupSql); if( zErr ){ json_set_err( FSL_JSON_E_UNKNOWN, "Repo-group update at least partially failed: %s", zErr); free(zErr); goto error; |
︙ | ︙ |
Changes to src/login.c.
︙ | ︙ | |||
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | " AND length(cookie)>30", uid); if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))"); zCookie = login_gen_user_cookie_value(zUsername, zHash); cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), bSessionCookie ? 0 : expires); record_login_attempt(zUsername, zIpAddr, 1); db_multi_exec("UPDATE user SET cookie=%Q," " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", zHash, expires, uid); fossil_free(zHash); if( zDest ){ *zDest = zCookie; }else{ free(zCookie); } } | > > | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | " AND length(cookie)>30", uid); if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))"); zCookie = login_gen_user_cookie_value(zUsername, zHash); cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), bSessionCookie ? 0 : expires); record_login_attempt(zUsername, zIpAddr, 1); db_unprotect(PROTECT_USER); db_multi_exec("UPDATE user SET cookie=%Q," " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", zHash, expires, uid); db_protect_pop(); fossil_free(zHash); if( zDest ){ *zDest = zCookie; }else{ free(zCookie); } } |
︙ | ︙ | |||
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | if(!g.userUid){ return; }else{ const char *cookie = login_cookie_name(); /* To logout, change the cookie value to an empty string */ cgi_set_cookie(cookie, "", login_cookie_path(), -86400); db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, " " cexpire=0 WHERE uid=%d" " AND login NOT IN ('anonymous','nobody'," " 'developer','reader')", g.userUid); cgi_replace_parameter(cookie, NULL); cgi_replace_parameter("anon", NULL); } } /* ** Return true if the prefix of zStr matches zPattern. Return false if | > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | if(!g.userUid){ return; }else{ const char *cookie = login_cookie_name(); /* To logout, change the cookie value to an empty string */ cgi_set_cookie(cookie, "", login_cookie_path(), -86400); db_unprotect(PROTECT_USER); db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, " " cexpire=0 WHERE uid=%d" " AND login NOT IN ('anonymous','nobody'," " 'developer','reader')", g.userUid); db_protect_pop(); cgi_replace_parameter(cookie, NULL); cgi_replace_parameter("anon", NULL); } } /* ** Return true if the prefix of zStr matches zPattern. Return false if |
︙ | ︙ | |||
578 579 580 581 582 583 584 585 586 587 | @ Your password is unchanged. @ </span></p> ; }else{ char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); char *zChngPw; char *zErr; db_multi_exec( "UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid ); | > > > < > | > > | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | @ Your password is unchanged. @ </span></p> ; }else{ char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); char *zChngPw; char *zErr; int rc; db_unprotect(PROTECT_USER); db_multi_exec( "UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid ); zChngPw = mprintf( "UPDATE user" " SET pw=shared_secret(%Q,%Q," " (SELECT value FROM config WHERE name='project-code'))" " WHERE login=%Q", zNew1, g.zLogin, g.zLogin ); fossil_free(zNewPw); rc = login_group_sql(zChngPw, "<p>", "</p>\n", &zErr); db_protect_pop(); if( rc ){ zErrMsg = mprintf("<span class=\"loginError\">%s</span>", zErr); fossil_free(zErr); }else{ redirect_to_g(); return; } } |
︙ | ︙ | |||
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | " AND cexpire>julianday('now')" " AND constant_time_cmp(cookie,%Q)=0", zLogin, zHash ); pStmt = 0; rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ db_multi_exec( "UPDATE user SET cookie=%Q, cexpire=%.17g" " WHERE login=%Q", zHash, sqlite3_column_double(pStmt, 0), zLogin ); nXfer++; } sqlite3_finalize(pStmt); } sqlite3_close(pOther); fossil_free(zOtherRepo); return nXfer; | > > | 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 | " AND cexpire>julianday('now')" " AND constant_time_cmp(cookie,%Q)=0", zLogin, zHash ); pStmt = 0; rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ db_unprotect(PROTECT_USER); db_multi_exec( "UPDATE user SET cookie=%Q, cexpire=%.17g" " WHERE login=%Q", zHash, sqlite3_column_double(pStmt, 0), zLogin ); db_protect_pop(); nXfer++; } sqlite3_finalize(pStmt); } sqlite3_close(pOther); fossil_free(zOtherRepo); return nXfer; |
︙ | ︙ | |||
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 | blob_init(&sql, 0, 0); blob_append_sql(&sql, "INSERT INTO user(login,pw,cap,info,mtime)\n" "VALUES(%Q,%Q,%Q," "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())", zUserID, zPass, zStartPerms, zDName, zEAddr, g.zIpAddr); fossil_free(zPass); db_multi_exec("%s", blob_sql_text(&sql)); uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID); login_set_user_cookie(zUserID, uid, NULL, 0); if( doAlerts ){ /* Also make the new user a subscriber. */ Blob hdr, body; AlertSender *pSender; sqlite3_int64 id; /* New subscriber Id */ | > > | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 | blob_init(&sql, 0, 0); blob_append_sql(&sql, "INSERT INTO user(login,pw,cap,info,mtime)\n" "VALUES(%Q,%Q,%Q," "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())", zUserID, zPass, zStartPerms, zDName, zEAddr, g.zIpAddr); fossil_free(zPass); db_unprotect(PROTECT_USER); db_multi_exec("%s", blob_sql_text(&sql)); db_protect_pop(); uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID); login_set_user_cookie(zUserID, uid, NULL, 0); if( doAlerts ){ /* Also make the new user a subscriber. */ Blob hdr, body; AlertSender *pSender; sqlite3_int64 id; /* New subscriber Id */ |
︙ | ︙ | |||
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 | zSelfCode ); while( db_step(&q)==SQLITE_ROW ){ const char *zRepoName = db_column_text(&q, 1); if( file_size(zRepoName, ExtFILE)<0 ){ /* Silently remove non-existent repositories from the login group. */ const char *zLabel = db_column_text(&q, 0); db_multi_exec( "DELETE FROM config WHERE name GLOB 'peer-*-%q'", &zLabel[10] ); continue; } rc = sqlite3_open_v2( zRepoName, &pPeer, SQLITE_OPEN_READWRITE, g.zVfsName ); | > > | 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 | zSelfCode ); while( db_step(&q)==SQLITE_ROW ){ const char *zRepoName = db_column_text(&q, 1); if( file_size(zRepoName, ExtFILE)<0 ){ /* Silently remove non-existent repositories from the login group. */ const char *zLabel = db_column_text(&q, 0); db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM config WHERE name GLOB 'peer-*-%q'", &zLabel[10] ); db_protect_pop(); continue; } rc = sqlite3_open_v2( zRepoName, &pPeer, SQLITE_OPEN_READWRITE, g.zVfsName ); |
︙ | ︙ | |||
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 | zSql = mprintf( "BEGIN;" "REPLACE INTO config(name,value,mtime) VALUES('peer-name-%q',%Q,now());" "REPLACE INTO config(name,value,mtime) VALUES('peer-repo-%q',%Q,now());" "COMMIT;", zSelfProjCode, zSelfLabel, zSelfProjCode, zSelfRepo ); login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); fossil_free(zSql); } /* ** Leave the login group that we are currently part of. */ void login_group_leave(char **pzErrMsg){ char *zProjCode; char *zSql; *pzErrMsg = 0; zProjCode = abbreviated_project_code(db_get("project-code","x")); zSql = mprintf( "DELETE FROM config WHERE name GLOB 'peer-*-%q';" "DELETE FROM config" " WHERE name='login-group-name'" " AND (SELECT count(*) FROM config WHERE name GLOB 'peer-*')==0;", zProjCode ); fossil_free(zProjCode); login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); fossil_free(zSql); db_multi_exec( "DELETE FROM config " " WHERE name GLOB 'peer-*'" " OR name GLOB 'login-group-*';" ); } /* ** COMMAND: login-group* ** ** Usage: %fossil login-group ** or: %fossil login-group join REPO [-name NAME] | > > > > | 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 | zSql = mprintf( "BEGIN;" "REPLACE INTO config(name,value,mtime) VALUES('peer-name-%q',%Q,now());" "REPLACE INTO config(name,value,mtime) VALUES('peer-repo-%q',%Q,now());" "COMMIT;", zSelfProjCode, zSelfLabel, zSelfProjCode, zSelfRepo ); db_unprotect(PROTECT_CONFIG); login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); db_protect_pop(); fossil_free(zSql); } /* ** Leave the login group that we are currently part of. */ void login_group_leave(char **pzErrMsg){ char *zProjCode; char *zSql; *pzErrMsg = 0; zProjCode = abbreviated_project_code(db_get("project-code","x")); zSql = mprintf( "DELETE FROM config WHERE name GLOB 'peer-*-%q';" "DELETE FROM config" " WHERE name='login-group-name'" " AND (SELECT count(*) FROM config WHERE name GLOB 'peer-*')==0;", zProjCode ); fossil_free(zProjCode); db_unprotect(PROTECT_CONFIG); login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); fossil_free(zSql); db_multi_exec( "DELETE FROM config " " WHERE name GLOB 'peer-*'" " OR name GLOB 'login-group-*';" ); db_protect_pop(); } /* ** COMMAND: login-group* ** ** Usage: %fossil login-group ** or: %fossil login-group join REPO [-name NAME] |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 | }else{ g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); g.zTop = &g.zBaseURL[7+strlen(zHost)]; g.zHttpsURL = mprintf("https://%s%.*s", zHost, i, zCur); } } if( db_is_writeable("repository") ){ if( !db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'", g.zBaseURL)){ db_multi_exec("INSERT INTO config(name,value,mtime)" "VALUES('baseurl:%q',1,now())", g.zBaseURL); }else{ db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" "VALUES('baseurl:%q',1,now())", g.zBaseURL ); } } } /* ** Send an HTTP redirect back to the designated Index Page. */ NORETURN void fossil_redirect_home(void){ | > > | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 | }else{ g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); g.zTop = &g.zBaseURL[7+strlen(zHost)]; g.zHttpsURL = mprintf("https://%s%.*s", zHost, i, zCur); } } if( db_is_writeable("repository") ){ db_unprotect(PROTECT_CONFIG); if( !db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'", g.zBaseURL)){ db_multi_exec("INSERT INTO config(name,value,mtime)" "VALUES('baseurl:%q',1,now())", g.zBaseURL); }else{ db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" "VALUES('baseurl:%q',1,now())", g.zBaseURL ); } db_protect_pop(); } } /* ** Send an HTTP redirect back to the designated Index Page. */ NORETURN void fossil_redirect_home(void){ |
︙ | ︙ |
Changes to src/manifest.c.
︙ | ︙ | |||
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){ blob_reset(pContent); blob_appendf(pErr, "line 1 not recognized"); return 0; } /* Then verify the Z-card. */ if( verify_z_card(z, n, pErr)==2 ){ blob_reset(pContent); return 0; } /* Allocate a Manifest object to hold the parsed control artifact. */ p = fossil_malloc( sizeof(*p) ); memset(p, 0, sizeof(*p)); memcpy(&p->content, pContent, sizeof(p->content)); p->rid = rid; | > > > > > > > > > | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){ blob_reset(pContent); blob_appendf(pErr, "line 1 not recognized"); return 0; } /* Then verify the Z-card. */ #if 1 /* Disable this ***ONLY*** (ONLY!) when testing hand-written inputs for card-related syntax errors. */ if( verify_z_card(z, n, pErr)==2 ){ blob_reset(pContent); return 0; } #else #warning ACHTUNG - z-card check is disabled for testing purposes. if(0 && verify_z_card(NULL, 0, NULL)){ /*avoid unused static func error*/ } #endif /* Allocate a Manifest object to hold the parsed control artifact. */ p = fossil_malloc( sizeof(*p) ); memset(p, 0, sizeof(*p)); memcpy(&p->content, pContent, sizeof(p->content)); p->rid = rid; |
︙ | ︙ | |||
599 600 601 602 603 604 605 606 607 608 609 610 611 612 | ** is when the specific event is said to occur. */ case 'E': { if( p->rEventDate>0.0 ) SYNTAX("more than one E-card"); p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0)); if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card"); p->zEventId = next_token(&x, &sz); if( !hname_validate(p->zEventId, sz) ){ SYNTAX("malformed hash on E-card"); } p->type = CFTYPE_EVENT; break; } | > | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | ** is when the specific event is said to occur. */ case 'E': { if( p->rEventDate>0.0 ) SYNTAX("more than one E-card"); p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0)); if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card"); p->zEventId = next_token(&x, &sz); if( p->zEventId==0 ) SYNTAX("missing hash on E-card"); if( !hname_validate(p->zEventId, sz) ){ SYNTAX("malformed hash on E-card"); } p->type = CFTYPE_EVENT; break; } |
︙ | ︙ | |||
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | if( zName==0 ) SYNTAX("missing filename on F-card"); defossilize(zName); if( !file_is_simple_pathname_nonstrict(zName) ){ SYNTAX("F-card filename is not a simple path"); } zUuid = next_token(&x, &sz); if( p->zBaseline==0 || zUuid!=0 ){ if( !hname_validate(zUuid,sz) ){ SYNTAX("F-card hash invalid"); } } zPerm = next_token(&x,0); zPriorName = next_token(&x,0); if( zPriorName ){ defossilize(zPriorName); if( !file_is_simple_pathname_nonstrict(zPriorName) ){ SYNTAX("F-card old filename is not a simple path"); } } if( p->nFile>=p->nFileAlloc ){ p->nFileAlloc = p->nFileAlloc*2 + 10; p->aFile = fossil_realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); } i = p->nFile++; p->aFile[i].zName = zName; p->aFile[i].zUuid = zUuid; p->aFile[i].zPerm = zPerm; p->aFile[i].zPrior = zPriorName; | > > > > > > > > > > > < < < | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 | if( zName==0 ) SYNTAX("missing filename on F-card"); defossilize(zName); if( !file_is_simple_pathname_nonstrict(zName) ){ SYNTAX("F-card filename is not a simple path"); } zUuid = next_token(&x, &sz); if( p->zBaseline==0 || zUuid!=0 ){ if( zUuid==0 ) SYNTAX("missing hash on F-card"); if( !hname_validate(zUuid,sz) ){ SYNTAX("F-card hash invalid"); } } zPerm = next_token(&x,0); zPriorName = next_token(&x,0); if( zPriorName ){ defossilize(zPriorName); if( !file_is_simple_pathname_nonstrict(zPriorName) ){ SYNTAX("F-card old filename is not a simple path"); } } if( p->nFile>=p->nFileAlloc ){ p->nFileAlloc = p->nFileAlloc*2 + 10; p->aFile = fossil_realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); } i = p->nFile++; if( i>0 && fossil_strcmp(p->aFile[i-1].zName, zName)>=0 ){ SYNTAX("incorrect F-card sort order"); } if( file_is_reserved_name(zName,-1) ){ /* If reserved names leaked into historical manifests due to ** slack oversight by older versions of Fossil, simply ignore ** those files */ p->nFile--; break; } p->aFile[i].zName = zName; p->aFile[i].zUuid = zUuid; p->aFile[i].zPerm = zPerm; p->aFile[i].zPrior = zPriorName; p->type = CFTYPE_MANIFEST; break; } /* ** G <hash> ** |
︙ | ︙ |
Changes to src/mkindex.c.
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #define CMDFLAG_WEBPAGE 0x0008 /* Web pages */ #define CMDFLAG_COMMAND 0x0010 /* A command */ #define CMDFLAG_SETTING 0x0020 /* A setting */ #define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */ #define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */ #define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */ #define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret webpage content */ /**************************************************************************/ /* ** Each entry looks like this: */ typedef struct Entry { int eType; /* CMDFLAG_* values */ | > | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #define CMDFLAG_WEBPAGE 0x0008 /* Web pages */ #define CMDFLAG_COMMAND 0x0010 /* A command */ #define CMDFLAG_SETTING 0x0020 /* A setting */ #define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */ #define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */ #define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */ #define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret webpage content */ #define CMDFLAG_SENSITIVE 0x0400 /* Security-sensitive setting */ /**************************************************************************/ /* ** Each entry looks like this: */ typedef struct Entry { int eType; /* CMDFLAG_* values */ |
︙ | ︙ | |||
246 247 248 249 250 251 252 253 254 255 256 257 258 259 | aEntry[nUsed].iWidth = 0; aEntry[nUsed].eType |= CMDFLAG_BOOLEAN; }else if( j==10 && strncmp(&zLine[i], "block-text", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_BOOLEAN); aEntry[nUsed].eType |= CMDFLAG_BLOCKTEXT; }else if( j==11 && strncmp(&zLine[i], "versionable", j)==0 ){ aEntry[nUsed].eType |= CMDFLAG_VERSIONABLE; }else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){ aEntry[nUsed].iWidth = atoi(&zLine[i+6]); }else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){ aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8); }else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){ aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9); }else{ | > > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | aEntry[nUsed].iWidth = 0; aEntry[nUsed].eType |= CMDFLAG_BOOLEAN; }else if( j==10 && strncmp(&zLine[i], "block-text", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_BOOLEAN); aEntry[nUsed].eType |= CMDFLAG_BLOCKTEXT; }else if( j==11 && strncmp(&zLine[i], "versionable", j)==0 ){ aEntry[nUsed].eType |= CMDFLAG_VERSIONABLE; }else if( j==9 && strncmp(&zLine[i], "sensitive", j)==0 ){ aEntry[nUsed].eType |= CMDFLAG_SENSITIVE; }else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){ aEntry[nUsed].iWidth = atoi(&zLine[i+6]); }else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){ aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8); }else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){ aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9); }else{ |
︙ | ︙ | |||
477 478 479 480 481 482 483 | } printf(" { \"%s\",%*s", z, (int)(20-strlen(z)), ""); if( zVar ){ printf(" \"%s\",%*s", zVar, (int)(15-strlen(zVar)), ""); }else{ printf(" 0,%*s", 16, ""); } | | > | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | } printf(" { \"%s\",%*s", z, (int)(20-strlen(z)), ""); if( zVar ){ printf(" \"%s\",%*s", zVar, (int)(15-strlen(zVar)), ""); }else{ printf(" 0,%*s", 16, ""); } printf(" %3d, %d, %d, %d, \"%s\"%*s },\n", aEntry[i].iWidth, (aEntry[i].eType & CMDFLAG_VERSIONABLE)!=0, (aEntry[i].eType & CMDFLAG_BLOCKTEXT)!=0, (aEntry[i].eType & CMDFLAG_SENSITIVE)!=0, zDef, (int)(10-strlen(zDef)), "" ); if( aEntry[i].zIf ){ printf("#endif\n"); } } printf("{0,0,0,0,0,0}};\n"); |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 | } fossil_errorlog("panic: %s", z); rc = fossil_print_error(rc, z); abort(); exit(rc); } NORETURN void fossil_fatal(const char *zFormat, ...){ char *z; int rc = 1; va_list ap; mainInFatalError = 1; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); rc = fossil_print_error(rc, z); fossil_free(z); | > > > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 | } fossil_errorlog("panic: %s", z); rc = fossil_print_error(rc, z); abort(); exit(rc); } NORETURN void fossil_fatal(const char *zFormat, ...){ static int once = 0; char *z; int rc = 1; if( once ) exit(1); once = 1; va_list ap; mainInFatalError = 1; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); rc = fossil_print_error(rc, z); fossil_free(z); |
︙ | ︙ |
Changes to src/rebuild.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | ); db_end_transaction(0); } /* Add the user.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "user", "mtime") ){ db_multi_exec( "CREATE TEMP TABLE temp_user AS SELECT * FROM user;" "DROP TABLE user;" "CREATE TABLE user(\n" " uid INTEGER PRIMARY KEY,\n" " login TEXT UNIQUE,\n" " pw TEXT,\n" " cap TEXT,\n" " cookie TEXT,\n" " ipaddr TEXT,\n" " cexpire DATETIME,\n" " info TEXT,\n" " mtime DATE,\n" " photo BLOB\n" ");" "INSERT OR IGNORE INTO user" " SELECT uid, login, pw, cap, cookie," " ipaddr, cexpire, info, now(), photo FROM temp_user;" "DROP TABLE temp_user;" ); } /* Add the config.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "config", "mtime") ){ db_multi_exec( "ALTER TABLE config ADD COLUMN mtime INTEGER;" "UPDATE config SET mtime=now();" ); } /* Add the shun.mtime and shun.scom columns if they are missing. ** (2011-04-27) */ if( !db_table_has_column("repository", "shun", "mtime") ){ db_multi_exec( | > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ); db_end_transaction(0); } /* Add the user.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "user", "mtime") ){ db_unprotect(PROTECT_ALL); db_multi_exec( "CREATE TEMP TABLE temp_user AS SELECT * FROM user;" "DROP TABLE user;" "CREATE TABLE user(\n" " uid INTEGER PRIMARY KEY,\n" " login TEXT UNIQUE,\n" " pw TEXT,\n" " cap TEXT,\n" " cookie TEXT,\n" " ipaddr TEXT,\n" " cexpire DATETIME,\n" " info TEXT,\n" " mtime DATE,\n" " photo BLOB\n" ");" "INSERT OR IGNORE INTO user" " SELECT uid, login, pw, cap, cookie," " ipaddr, cexpire, info, now(), photo FROM temp_user;" "DROP TABLE temp_user;" ); db_protect_pop(); } /* Add the config.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "config", "mtime") ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "ALTER TABLE config ADD COLUMN mtime INTEGER;" "UPDATE config SET mtime=now();" ); db_protect_pop(); } /* Add the shun.mtime and shun.scom columns if they are missing. ** (2011-04-27) */ if( !db_table_has_column("repository", "shun", "mtime") ){ db_multi_exec( |
︙ | ︙ | |||
380 381 382 383 384 385 386 387 388 389 390 391 392 393 | processCnt = 0; if (ttyOutput && !g.fQuiet) { percent_complete(0); } alert_triggers_disable(); rebuild_update_schema(); blob_init(&sql, 0, 0); db_prepare(&q, "SELECT name FROM sqlite_schema /*scan*/" " WHERE type='table'" " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias'," "'config','shun','private','reportfmt'," "'concealed','accesslog','modreq'," "'purgeevent','purgeitem','unversioned'," | > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | processCnt = 0; if (ttyOutput && !g.fQuiet) { percent_complete(0); } alert_triggers_disable(); rebuild_update_schema(); blob_init(&sql, 0, 0); db_unprotect(PROTECT_ALL); db_prepare(&q, "SELECT name FROM sqlite_schema /*scan*/" " WHERE type='table'" " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias'," "'config','shun','private','reportfmt'," "'concealed','accesslog','modreq'," "'purgeevent','purgeitem','unversioned'," |
︙ | ︙ | |||
473 474 475 476 477 478 479 480 481 482 483 484 485 486 | percent_complete((processCnt*1000)/totalSize); } alert_triggers_enable(); if(!g.fQuiet && ttyOutput ){ percent_complete(1000); fossil_print("\n"); } return errCnt; } /* ** Number of neighbors to search */ #define N_NEIGHBOR 5 | > | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | percent_complete((processCnt*1000)/totalSize); } alert_triggers_enable(); if(!g.fQuiet && ttyOutput ){ percent_complete(1000); fossil_print("\n"); } db_protect_pop(); return errCnt; } /* ** Number of neighbors to search */ #define N_NEIGHBOR 5 |
︙ | ︙ | |||
665 666 667 668 669 670 671 672 673 674 675 676 677 678 | return; } /* We should be done with options.. */ verify_all_options(); db_begin_transaction(); if( !compressOnlyFlag ){ search_drop_index(); ttyOutput = 1; errCnt = rebuild_db(randomizeFlag, 1, doClustering); reconstruct_private_table(); } db_multi_exec( | > | 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 | return; } /* We should be done with options.. */ verify_all_options(); db_begin_transaction(); db_unprotect(PROTECT_ALL); if( !compressOnlyFlag ){ search_drop_index(); ttyOutput = 1; errCnt = rebuild_db(randomizeFlag, 1, doClustering); reconstruct_private_table(); } db_multi_exec( |
︙ | ︙ | |||
718 719 720 721 722 723 724 725 726 727 728 729 730 731 | fossil_print("done\n"); } if( activateWal ){ db_multi_exec("PRAGMA journal_mode=WAL;"); } } if( runReindex ) search_rebuild_index(); if( showStats ){ static const struct { int idx; const char *zLabel; } aStat[] = { { CFTYPE_ANY, "Artifacts:" }, { CFTYPE_MANIFEST, "Manifests:" }, { CFTYPE_CLUSTER, "Clusters:" }, { CFTYPE_CONTROL, "Tags:" }, { CFTYPE_WIKI, "Wikis:" }, | > | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | fossil_print("done\n"); } if( activateWal ){ db_multi_exec("PRAGMA journal_mode=WAL;"); } } if( runReindex ) search_rebuild_index(); db_protect_pop(); if( showStats ){ static const struct { int idx; const char *zLabel; } aStat[] = { { CFTYPE_ANY, "Artifacts:" }, { CFTYPE_MANIFEST, "Manifests:" }, { CFTYPE_CLUSTER, "Clusters:" }, { CFTYPE_CONTROL, "Tags:" }, { CFTYPE_WIKI, "Wikis:" }, |
︙ | ︙ | |||
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 | ** the repository from ever again pushing or pulling to other ** repositories. Used to create a "test" repository for development ** testing by cloning a working project repository. */ void test_detach_cmd(void){ db_find_and_open_repository(0, 2); db_begin_transaction(); db_multi_exec( "DELETE FROM config WHERE name GLOB 'last-sync-*';" "DELETE FROM config WHERE name GLOB 'sync-*:*';" "UPDATE config SET value=lower(hex(randomblob(20)))" " WHERE name='project-code';" "UPDATE config SET value='detached-' || value" " WHERE name='project-name' AND value NOT GLOB 'detached-*';" ); db_end_transaction(0); } /* ** COMMAND: test-create-clusters ** ** Create clusters for all unclustered artifacts if the number of unclustered | > > | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | ** the repository from ever again pushing or pulling to other ** repositories. Used to create a "test" repository for development ** testing by cloning a working project repository. */ void test_detach_cmd(void){ db_find_and_open_repository(0, 2); db_begin_transaction(); db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM config WHERE name GLOB 'last-sync-*';" "DELETE FROM config WHERE name GLOB 'sync-*:*';" "UPDATE config SET value=lower(hex(randomblob(20)))" " WHERE name='project-code';" "UPDATE config SET value='detached-' || value" " WHERE name='project-name' AND value NOT GLOB 'detached-*';" ); db_protect_pop(); db_end_transaction(0); } /* ** COMMAND: test-create-clusters ** ** Create clusters for all unclustered artifacts if the number of unclustered |
︙ | ︙ | |||
908 909 910 911 912 913 914 915 916 917 918 919 920 921 | } db_begin_transaction(); if( privateOnly || bVerily ){ bNeedRebuild = db_exists("SELECT 1 FROM private"); delete_private_content(); } if( !privateOnly ){ db_multi_exec( "UPDATE user SET pw='';" "DELETE FROM config WHERE name GLOB 'last-sync-*';" "DELETE FROM config WHERE name GLOB 'sync-*:*';" "DELETE FROM config WHERE name GLOB 'peer-*';" "DELETE FROM config WHERE name GLOB 'login-group-*';" "DELETE FROM config WHERE name GLOB 'skin:*';" | > | 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | } db_begin_transaction(); if( privateOnly || bVerily ){ bNeedRebuild = db_exists("SELECT 1 FROM private"); delete_private_content(); } if( !privateOnly ){ db_unprotect(PROTECT_ALL); db_multi_exec( "UPDATE user SET pw='';" "DELETE FROM config WHERE name GLOB 'last-sync-*';" "DELETE FROM config WHERE name GLOB 'sync-*:*';" "DELETE FROM config WHERE name GLOB 'peer-*';" "DELETE FROM config WHERE name GLOB 'login-group-*';" "DELETE FROM config WHERE name GLOB 'skin:*';" |
︙ | ︙ | |||
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 | "UPDATE user SET photo=NULL, info='';\n" "DROP TABLE IF EXISTS purgeevent;\n" "DROP TABLE IF EXISTS purgeitem;\n" "DROP TABLE IF EXISTS admin_log;\n" "DROP TABLE IF EXISTS vcache;\n" ); } } if( !bNeedRebuild ){ db_end_transaction(0); db_multi_exec("VACUUM;"); }else{ rebuild_db(0, 1, 0); db_end_transaction(0); } } /* | > > > | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 | "UPDATE user SET photo=NULL, info='';\n" "DROP TABLE IF EXISTS purgeevent;\n" "DROP TABLE IF EXISTS purgeitem;\n" "DROP TABLE IF EXISTS admin_log;\n" "DROP TABLE IF EXISTS vcache;\n" ); } db_protect_pop(); } if( !bNeedRebuild ){ db_end_transaction(0); db_unprotect(PROTECT_ALL); db_multi_exec("VACUUM;"); db_protect_pop(); }else{ rebuild_db(0, 1, 0); db_end_transaction(0); } } /* |
︙ | ︙ |
Changes to src/report.c.
︙ | ︙ | |||
228 229 230 231 232 233 234 | return rc; } /* ** Activate the query authorizer */ void report_restrict_sql(char **pzErr){ | | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | return rc; } /* ** Activate the query authorizer */ void report_restrict_sql(char **pzErr){ db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report"); sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000); } void report_unrestrict_sql(void){ db_clear_authorizer(); } /* ** Check the given SQL to see if is a valid query that does not ** attempt to do anything dangerous. Return 0 on success and a ** pointer to an error message string (obtained from malloc) if |
︙ | ︙ | |||
678 679 680 681 682 683 684 | /* Do initialization */ if( pState->nCount==0 ){ /* Turn off the authorizer. It is no longer doing anything since the ** query has already been prepared. */ | | | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | /* Do initialization */ if( pState->nCount==0 ){ /* Turn off the authorizer. It is no longer doing anything since the ** query has already been prepared. */ db_clear_authorizer(); /* Figure out the number of columns, the column that determines background ** color, and whether or not this row of data is represented by multiple ** rows in the table. */ pState->nCol = 0; pState->isMultirow = 0; |
︙ | ︙ |
Changes to src/security_audit.c.
︙ | ︙ | |||
279 280 281 282 283 284 285 286 287 288 289 290 291 292 | @ Anonymous users can act as moderators for wiki, tickets, or @ forum posts. This defeats the whole purpose of moderation. @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum" @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5") @ from users "anonymous" and "nobody" @ on the <a href="setup_ulist">User Configuration</a> page. } /* Obsolete: */ if( hasAnyCap(zAnonCap, "d") || hasAnyCap(zDevCap, "d") || hasAnyCap(zReadCap, "d") ){ @ <li><p><b>WARNING:</b> @ One or more users has the <a | > > > > > > > > | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | @ Anonymous users can act as moderators for wiki, tickets, or @ forum posts. This defeats the whole purpose of moderation. @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum" @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5") @ from users "anonymous" and "nobody" @ on the <a href="setup_ulist">User Configuration</a> page. } /* The strict-manifest-syntax setting should be on. */ if( db_get_boolean("strict-manifest-syntax",1)==0 ){ @ <li><p><b>WARNING:</b> @ The "strict-manifest-syntax" flag is off. This is a security @ risk. Turn this setting on (its default) to protect the users @ of this repository. } /* Obsolete: */ if( hasAnyCap(zAnonCap, "d") || hasAnyCap(zDevCap, "d") || hasAnyCap(zReadCap, "d") ){ @ <li><p><b>WARNING:</b> @ One or more users has the <a |
︙ | ︙ | |||
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | return; } if( P("cancel") ){ /* User pressed the cancel button. Go back */ cgi_redirect("secaudit0"); } if( P("apply") ){ db_multi_exec( "UPDATE user SET cap=''" " WHERE login IN ('nobody','anonymous');" "DELETE FROM config WHERE name='public-pages';" ); db_set("self-register","0",0); cgi_redirect("secaudit0"); } style_header("Make This Website Private"); @ <p>Click the "Make It Private" button below to disable all @ anonymous access to this repository. A valid login and password @ will be required to access this repository after clicking that | > > | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | return; } if( P("cancel") ){ /* User pressed the cancel button. Go back */ cgi_redirect("secaudit0"); } if( P("apply") ){ db_unprotect(PROTECT_USER); db_multi_exec( "UPDATE user SET cap=''" " WHERE login IN ('nobody','anonymous');" "DELETE FROM config WHERE name='public-pages';" ); db_protect_pop(); db_set("self-register","0",0); cgi_redirect("secaudit0"); } style_header("Make This Website Private"); @ <p>Click the "Make It Private" button below to disable all @ anonymous access to this repository. A valid login and password @ will be required to access this repository after clicking that |
︙ | ︙ |
Changes to src/setup.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** Increment the "cfgcnt" variable, so that ETags will know that ** the configuration has changed. */ void setup_incr_cfgcnt(void){ static int once = 1; if( once ){ once = 0; db_multi_exec("UPDATE config SET value=value+1 WHERE name='cfgcnt'"); if( db_changes()==0 ){ db_multi_exec("INSERT INTO config(name,value) VALUES('cfgcnt',1)"); } } } /* ** Output a single entry for a menu generated using an HTML table. ** If zLink is not NULL or an empty string, then it is the page that ** the menu entry will hyperlink to. If zLink is NULL or "", then | > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ** Increment the "cfgcnt" variable, so that ETags will know that ** the configuration has changed. */ void setup_incr_cfgcnt(void){ static int once = 1; if( once ){ once = 0; db_unprotect(PROTECT_CONFIG); db_multi_exec("UPDATE config SET value=value+1 WHERE name='cfgcnt'"); if( db_changes()==0 ){ db_multi_exec("INSERT INTO config(name,value) VALUES('cfgcnt',1)"); } db_protect_pop(); } } /* ** Output a single entry for a menu generated using an HTML table. ** If zLink is not NULL or an empty string, then it is the page that ** the menu entry will hyperlink to. If zLink is NULL or "", then |
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | if( zQ==0 && !disabled && P("submit") ){ zQ = "off"; } if( zQ ){ int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); if( iQ!=iVal ){ login_verify_csrf_secret(); db_set(zVar, iQ ? "1" : "0", 0); setup_incr_cfgcnt(); admin_log("Set option [%q] to [%q].", zVar, iQ ? "on" : "off"); iVal = iQ; } } @ <label><input type="checkbox" name="%s(zQParm)" \ | > > | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | if( zQ==0 && !disabled && P("submit") ){ zQ = "off"; } if( zQ ){ int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); if( iQ!=iVal ){ login_verify_csrf_secret(); db_protect_only(PROTECT_NONE); db_set(zVar, iQ ? "1" : "0", 0); db_protect_pop(); setup_incr_cfgcnt(); admin_log("Set option [%q] to [%q].", zVar, iQ ? "on" : "off"); iVal = iQ; } } @ <label><input type="checkbox" name="%s(zQParm)" \ |
︙ | ︙ | |||
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | ){ const char *zVal = db_get(zVar, zDflt); const char *zQ = P(zQParm); if( zQ && fossil_strcmp(zQ,zVal)!=0 ){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); setup_incr_cfgcnt(); db_set(zVar, zQ, 0); admin_log("Set entry_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); zVal = zQ; } @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \ @ id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)" \ if( disabled ){ | > > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | ){ const char *zVal = db_get(zVar, zDflt); const char *zQ = P(zQParm); if( zQ && fossil_strcmp(zQ,zVal)!=0 ){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); setup_incr_cfgcnt(); db_protect_only(PROTECT_NONE); db_set(zVar, zQ, 0); db_protect_pop(); admin_log("Set entry_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); zVal = zQ; } @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \ @ id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)" \ if( disabled ){ |
︙ | ︙ | |||
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | int disabled /* 1 if the textarea should not be editable */ ){ const char *z = db_get(zVar, zDflt); const char *zQ = P(zQP); if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); db_set(zVar, zQ, 0); setup_incr_cfgcnt(); admin_log("Set textarea_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); z = zQ; } if( rows>0 && cols>0 ){ @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" \ | > > | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | int disabled /* 1 if the textarea should not be editable */ ){ const char *z = db_get(zVar, zDflt); const char *zQ = P(zQP); if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); db_protect_only(PROTECT_NONE); db_set(zVar, zQ, 0); db_protect_pop(); setup_incr_cfgcnt(); admin_log("Set textarea_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); z = zQ; } if( rows>0 && cols>0 ){ @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" \ |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 | login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } db_begin_transaction(); if( P("clear")!=0 && cgi_csrf_safe(1) ){ db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'"); cgi_replace_parameter("adunit",""); cgi_replace_parameter("adright",""); setup_incr_cfgcnt(); } style_header("Edit Ad Unit"); @ <form action="%s(g.zTop)/setup_adunit" method="post"><div> | > > | 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } db_begin_transaction(); if( P("clear")!=0 && cgi_csrf_safe(1) ){ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'"); db_protect_pop(); cgi_replace_parameter("adunit",""); cgi_replace_parameter("adright",""); setup_incr_cfgcnt(); } style_header("Edit Ad Unit"); @ <form action="%s(g.zTop)/setup_adunit" method="post"><div> |
︙ | ︙ | |||
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 | } login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } db_begin_transaction(); if( !cgi_csrf_safe(1) ){ /* Allow no state changes if not safe from CSRF */ }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){ Blob img; Stmt ins; blob_init(&img, aLogoImg, szLogoImg); db_prepare(&ins, | > | 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 | } login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } db_begin_transaction(); db_unprotect(PROTECT_CONFIG); if( !cgi_csrf_safe(1) ){ /* Allow no state changes if not safe from CSRF */ }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){ Blob img; Stmt ins; blob_init(&img, aLogoImg, szLogoImg); db_prepare(&ins, |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 | ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("setbg")!=0 && zBgMime && zBgMime[0] && szBgImg>0 ){ Blob img; Stmt ins; blob_init(&img, aBgImg, szBgImg); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" " VALUES('background-image',:bytes,now())" ); db_bind_blob(&ins, ":bytes", &img); db_step(&ins); db_finalize(&ins); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('background-mimetype',%Q,now())", zBgMime ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("clrbg")!=0 ){ db_multi_exec( "DELETE FROM config WHERE name IN " "('background-image','background-mimetype')" ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("seticon")!=0 && zIconMime && zIconMime[0] && szIconImg>0 ){ Blob img; Stmt ins; blob_init(&img, aIconImg, szIconImg); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" " VALUES('icon-image',:bytes,now())" ); db_bind_blob(&ins, ":bytes", &img); db_step(&ins); db_finalize(&ins); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('icon-mimetype',%Q,now())", zIconMime ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("clricon")!=0 ){ db_multi_exec( "DELETE FROM config WHERE name IN " "('icon-image','icon-mimetype')" ); | > > > > > | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 | ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("setbg")!=0 && zBgMime && zBgMime[0] && szBgImg>0 ){ Blob img; Stmt ins; blob_init(&img, aBgImg, szBgImg); db_unprotect(PROTECT_CONFIG); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" " VALUES('background-image',:bytes,now())" ); db_bind_blob(&ins, ":bytes", &img); db_step(&ins); db_finalize(&ins); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('background-mimetype',%Q,now())", zBgMime ); db_protect_pop(); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("clrbg")!=0 ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM config WHERE name IN " "('background-image','background-mimetype')" ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("seticon")!=0 && zIconMime && zIconMime[0] && szIconImg>0 ){ Blob img; Stmt ins; blob_init(&img, aIconImg, szIconImg); db_unprotect(PROTECT_CONFIG); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" " VALUES('icon-image',:bytes,now())" ); db_bind_blob(&ins, ":bytes", &img); db_step(&ins); db_finalize(&ins); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('icon-mimetype',%Q,now())", zIconMime ); db_protect_pop(); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("clricon")!=0 ){ db_multi_exec( "DELETE FROM config WHERE name IN " "('icon-image','icon-mimetype')" ); |
︙ | ︙ | |||
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 | const char *zOldName, const char *zNewName, const char *zValue ){ if( !cgi_csrf_safe(1) ) return; if( zNewName[0]==0 || zValue[0]==0 ){ if( zOldName[0] ){ blob_append_sql(pSql, "DELETE FROM config WHERE name='walias:%q';\n", zOldName); } return; } if( zOldName[0]==0 ){ blob_append_sql(pSql, "INSERT INTO config(name,value,mtime) VALUES('walias:%q',%Q,now());\n", zNewName, zValue); return; } if( strcmp(zOldName, zNewName)!=0 ){ blob_append_sql(pSql, "UPDATE config SET name='walias:%q', value=%Q, mtime=now()" " WHERE name='walias:%q';\n", zNewName, zValue, zOldName); }else{ blob_append_sql(pSql, "UPDATE config SET value=%Q, mtime=now()" " WHERE name='walias:%q' AND value<>%Q;\n", zValue, zOldName, zValue); } } /* ** WEBPAGE: waliassetup ** ** Configure the URL aliases */ | > > > > > > | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 | const char *zOldName, const char *zNewName, const char *zValue ){ if( !cgi_csrf_safe(1) ) return; if( zNewName[0]==0 || zValue[0]==0 ){ if( zOldName[0] ){ db_unprotect(PROTECT_CONFIG); blob_append_sql(pSql, "DELETE FROM config WHERE name='walias:%q';\n", zOldName); db_protect_pop(); } return; } if( zOldName[0]==0 ){ db_unprotect(PROTECT_CONFIG); blob_append_sql(pSql, "INSERT INTO config(name,value,mtime) VALUES('walias:%q',%Q,now());\n", zNewName, zValue); db_protect_pop(); return; } db_unprotect(PROTECT_CONFIG); if( strcmp(zOldName, zNewName)!=0 ){ blob_append_sql(pSql, "UPDATE config SET name='walias:%q', value=%Q, mtime=now()" " WHERE name='walias:%q';\n", zNewName, zValue, zOldName); }else{ blob_append_sql(pSql, "UPDATE config SET value=%Q, mtime=now()" " WHERE name='walias:%q' AND value<>%Q;\n", zValue, zOldName, zValue); } db_protect_pop(); } /* ** WEBPAGE: waliassetup ** ** Configure the URL aliases */ |
︙ | ︙ |
Changes to src/setupuser.c.
︙ | ︙ | |||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | } /* Check for requests to delete the user */ if( P("delete") && cgi_csrf_safe(1) ){ int n; if( P("verifydelete") ){ /* Verified delete user request */ db_multi_exec("DELETE FROM user WHERE uid=%d", uid); moderation_disapprove_for_missing_users(); admin_log("Deleted user [%s] (uid %d).", PD("login","???")/*safe-for-%s*/, uid); cgi_redirect(cgi_referer("setup_ulist")); return; } n = db_int(0, "SELECT count(*) FROM event" | > > | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | } /* Check for requests to delete the user */ if( P("delete") && cgi_csrf_safe(1) ){ int n; if( P("verifydelete") ){ /* Verified delete user request */ db_unprotect(PROTECT_USER); db_multi_exec("DELETE FROM user WHERE uid=%d", uid); db_protect_pop(); moderation_disapprove_for_missing_users(); admin_log("Deleted user [%s] (uid %d).", PD("login","???")/*safe-for-%s*/, uid); cgi_redirect(cgi_referer("setup_ulist")); return; } n = db_int(0, "SELECT count(*) FROM event" |
︙ | ︙ | |||
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | @ @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> @ [Bummer]</a></p> style_footer(); return; } login_verify_csrf_secret(); db_multi_exec( "REPLACE INTO user(uid,login,info,pw,cap,mtime) " "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())", uid, zLogin, P("info"), zPw, zCap ); setup_incr_cfgcnt(); admin_log( "Updated user [%q] with capabilities [%q].", zLogin, zCap ); if( atoi(PD("all","0"))>0 ){ Blob sql; char *zErr = 0; blob_zero(&sql); | > > | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | @ @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> @ [Bummer]</a></p> style_footer(); return; } login_verify_csrf_secret(); db_unprotect(PROTECT_USER); db_multi_exec( "REPLACE INTO user(uid,login,info,pw,cap,mtime) " "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())", uid, zLogin, P("info"), zPw, zCap ); db_protect_pop(); setup_incr_cfgcnt(); admin_log( "Updated user [%q] with capabilities [%q].", zLogin, zCap ); if( atoi(PD("all","0"))>0 ){ Blob sql; char *zErr = 0; blob_zero(&sql); |
︙ | ︙ | |||
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | " info=%Q," " cap=%Q," " mtime=now()" " WHERE login=%Q;", zLogin, P("pw"), zLogin, P("info"), zCap, zOldLogin ); login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr); blob_reset(&sql); admin_log( "Updated user [%q] in all login groups " "with capabilities [%q].", zLogin, zCap ); if( zErr ){ const char *zRef = cgi_referer("setup_ulist"); style_header("User Change Error"); | > > | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | " info=%Q," " cap=%Q," " mtime=now()" " WHERE login=%Q;", zLogin, P("pw"), zLogin, P("info"), zCap, zOldLogin ); db_unprotect(PROTECT_USER); login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr); db_protect_pop(); blob_reset(&sql); admin_log( "Updated user [%q] in all login groups " "with capabilities [%q].", zLogin, zCap ); if( zErr ){ const char *zRef = cgi_referer("setup_ulist"); style_header("User Change Error"); |
︙ | ︙ |
Changes to src/skins.c.
︙ | ︙ | |||
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | z = db_get(azSkinFile[i], 0); if( z==0 ){ zLabel = mprintf("skins/default/%s.txt", azSkinFile[i]); z = builtin_text(zLabel); fossil_free(zLabel); } } blob_appendf(&val, "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now());\n", azSkinFile[i], z ); } return blob_str(&val); } /* ** Respond to a Rename button press. Return TRUE if a dialog was painted. ** Return FALSE to continue with the main Skins page. | > > | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | z = db_get(azSkinFile[i], 0); if( z==0 ){ zLabel = mprintf("skins/default/%s.txt", azSkinFile[i]); z = builtin_text(zLabel); fossil_free(zLabel); } } db_unprotect(PROTECT_CONFIG); blob_appendf(&val, "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now());\n", azSkinFile[i], z ); db_protect_pop(); } return blob_str(&val); } /* ** Respond to a Rename button press. Return TRUE if a dialog was painted. ** Return FALSE to continue with the main Skins page. |
︙ | ︙ | |||
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | @ <input type="submit" name="canren" value="Cancel"> @ </table> login_insert_csrf_secret(); @ </div></form> style_footer(); return 1; } db_multi_exec( "UPDATE config SET name='skin:%q' WHERE name='skin:%q';", zNewName, zOldName ); return 0; } /* ** Respond to a Save button press. Return TRUE if a dialog was painted. ** Return FALSE to continue with the main Skins page. */ | > > | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | @ <input type="submit" name="canren" value="Cancel"> @ </table> login_insert_csrf_secret(); @ </div></form> style_footer(); return 1; } db_unprotect(PROTECT_CONFIG); db_multi_exec( "UPDATE config SET name='skin:%q' WHERE name='skin:%q';", zNewName, zOldName ); db_protect_pop(); return 0; } /* ** Respond to a Save button press. Return TRUE if a dialog was painted. ** Return FALSE to continue with the main Skins page. */ |
︙ | ︙ | |||
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | @ <input type="submit" name="cansave" value="Cancel"> @ </table> login_insert_csrf_secret(); @ </div></form> style_footer(); return 1; } db_multi_exec( "INSERT OR IGNORE INTO config(name, value, mtime)" "VALUES('skin:%q',%Q,now())", zNewName, zCurrent ); return 0; } /* ** WEBPAGE: setup_skin_admin ** ** Administrative actions on skins. For administrators only. | > > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | @ <input type="submit" name="cansave" value="Cancel"> @ </table> login_insert_csrf_secret(); @ </div></form> style_footer(); return 1; } db_unprotect(PROTECT_CONFIG); db_multi_exec( "INSERT OR IGNORE INTO config(name, value, mtime)" "VALUES('skin:%q',%Q,now())", zNewName, zCurrent ); db_protect_pop(); return 0; } /* ** WEBPAGE: setup_skin_admin ** ** Administrative actions on skins. For administrators only. |
︙ | ︙ | |||
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | login_insert_csrf_secret(); @ </div></form> style_footer(); db_end_transaction(1); return; } if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } if( P("draftdel")!=0 ){ const char *zDraft = P("name"); if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ db_multi_exec("DELETE FROM config WHERE name GLOB '%q-*'", zDraft); } } if( skinRename() || skinSave(zCurrent) ){ db_end_transaction(0); return; } | > > > > | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | login_insert_csrf_secret(); @ </div></form> style_footer(); db_end_transaction(1); return; } if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name=%Q", zName); db_protect_pop(); } if( P("draftdel")!=0 ){ const char *zDraft = P("name"); if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name GLOB '%q-*'", zDraft); db_protect_pop(); } } if( skinRename() || skinSave(zCurrent) ){ db_end_transaction(0); return; } |
︙ | ︙ | |||
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | break; } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); if( !seen ){ db_multi_exec( "INSERT INTO config(name,value,mtime) VALUES(" " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," " %Q,now())", zCurrent ); } } seen = 0; for(i=0; i<count(aBuiltinSkin); i++){ if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){ seen = 1; zCurrent = aBuiltinSkin[i].zSQL; | > > | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | break; } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); if( !seen ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "INSERT INTO config(name,value,mtime) VALUES(" " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," " %Q,now())", zCurrent ); db_protect_pop(); } } seen = 0; for(i=0; i<count(aBuiltinSkin); i++){ if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){ seen = 1; zCurrent = aBuiltinSkin[i].zSQL; |
︙ | ︙ | |||
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); } if( !seen ){ db_multi_exec( "INSERT INTO config(name,value,mtime) VALUES(" " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," " %Q,now())", zCurrent ); } /* Publish draft iSkin */ for(i=0; i<count(azSkinFile); i++){ char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]); db_set(azSkinFile[i], zNew, 0); } | > > | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 | } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); } if( !seen ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "INSERT INTO config(name,value,mtime) VALUES(" " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," " %Q,now())", zCurrent ); db_protect_pop(); } /* Publish draft iSkin */ for(i=0; i<count(azSkinFile); i++){ char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]); db_set(azSkinFile[i], zNew, 0); } |
︙ | ︙ |
Changes to src/sqlcmd.c.
︙ | ︙ | |||
151 152 153 154 155 156 157 158 159 160 161 162 163 164 | sqlcmd_compress, 0, 0); sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0, sqlcmd_decompress, 0, 0); sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0, sqlcmd_gather_artifact_stats, 0, 0); return SQLITE_OK; } /* ** This is the "automatic extension" initializer that runs right after ** the connection to the repository database is opened. Set up the ** database connection to be more useful to the human operator. */ static int sqlcmd_autoinit( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | sqlcmd_compress, 0, 0); sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0, sqlcmd_decompress, 0, 0); sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0, sqlcmd_gather_artifact_stats, 0, 0); return SQLITE_OK; } /* ** Undocumented test SQL functions: ** ** db_protect(X) ** db_protect_pop(X) ** ** These invoke the corresponding C routines. Misuse may result in ** an assertion fault. */ static void sqlcmd_db_protect( sqlite3_context *context, int argc, sqlite3_value **argv ){ unsigned mask = 0; const char *z = (const char*)sqlite3_value_text(argv[0]); if( sqlite3_stricmp(z,"user")==0 ) mask |= PROTECT_USER; if( sqlite3_stricmp(z,"config")==0 ) mask |= PROTECT_CONFIG; if( sqlite3_stricmp(z,"sensitive")==0 ) mask |= PROTECT_SENSITIVE; if( sqlite3_stricmp(z,"readonly")==0 ) mask |= PROTECT_READONLY; if( sqlite3_stricmp(z,"all")==0 ) mask |= PROTECT_ALL; db_protect(mask); } static void sqlcmd_db_protect_pop( sqlite3_context *context, int argc, sqlite3_value **argv ){ db_protect_pop(); } /* ** This is the "automatic extension" initializer that runs right after ** the connection to the repository database is opened. Set up the ** database connection to be more useful to the human operator. */ static int sqlcmd_autoinit( |
︙ | ︙ | |||
191 192 193 194 195 196 197 198 199 200 201 202 203 204 | sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); } /* Arrange to trace close operations so that static prepared statements ** will get cleaned up when the shell closes the database connection */ if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE; sqlite3_trace_v2(db, mTrace, db_sql_trace, 0); return SQLITE_OK; } /* ** atexit() handler that cleans up global state modified by this module. */ static void sqlcmd_atexit(void) { | > > > > > > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); } /* Arrange to trace close operations so that static prepared statements ** will get cleaned up when the shell closes the database connection */ if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE; sqlite3_trace_v2(db, mTrace, db_sql_trace, 0); db_protect_only(PROTECT_NONE); sqlite3_set_authorizer(db, db_top_authorizer, db); sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0, sqlcmd_db_protect, 0, 0); sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0, sqlcmd_db_protect_pop, 0, 0); return SQLITE_OK; } /* ** atexit() handler that cleans up global state modified by this module. */ static void sqlcmd_atexit(void) { |
︙ | ︙ |
Changes to src/stash.c.
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 343 344 345 | db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew); db_ephemeral_blob(&q, 6, &delta); blob_write_to_file(&delta, zNPath); file_setexe(zNPath, isExec); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); file_delete(zOPath); }else{ Blob a, b, out, disk; int isNewLink = file_islink(zOPath); db_ephemeral_blob(&q, 6, &delta); blob_read_from_file(&disk, zOPath, RepoFILE); content_get(rid, &a); blob_delta_apply(&a, &delta, &b); | > > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew); db_ephemeral_blob(&q, 6, &delta); blob_write_to_file(&delta, zNPath); file_setexe(zNPath, isExec); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); file_delete(zOPath); }else if( file_unsafe_in_tree_path(zNPath) ){ /* Ignore the unsafe path */ }else{ Blob a, b, out, disk; int isNewLink = file_islink(zOPath); db_ephemeral_blob(&q, 6, &delta); blob_read_from_file(&disk, zOPath, RepoFILE); content_get(rid, &a); blob_delta_apply(&a, &delta, &b); |
︙ | ︙ |
Changes to src/sync.c.
︙ | ︙ | |||
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | nArg = (int)strlen(zArg); if( strcmp(zArg,"off")==0 ){ /* fossil remote off ** Forget the last-sync-URL and its password */ if( g.argc!=3 ) usage("off"); remote_delete_default: db_multi_exec( "DELETE FROM config WHERE name GLOB 'last-sync-*';" ); return; } if( strncmp(zArg, "list", nArg)==0 || strcmp(zArg,"ls")==0 ){ Stmt q; if( g.argc!=3 ) usage("list"); db_prepare(&q, "SELECT 'default', value FROM config WHERE name='last-sync-url'" | > > | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | nArg = (int)strlen(zArg); if( strcmp(zArg,"off")==0 ){ /* fossil remote off ** Forget the last-sync-URL and its password */ if( g.argc!=3 ) usage("off"); remote_delete_default: db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM config WHERE name GLOB 'last-sync-*';" ); db_protect_pop(); return; } if( strncmp(zArg, "list", nArg)==0 || strcmp(zArg,"ls")==0 ){ Stmt q; if( g.argc!=3 ) usage("list"); db_prepare(&q, "SELECT 'default', value FROM config WHERE name='last-sync-url'" |
︙ | ︙ | |||
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | if( g.argc!=5 ) usage("add NAME URL"); memset(&x, 0, sizeof(x)); zName = g.argv[3]; zUrl = g.argv[4]; if( strcmp(zName,"default")==0 ) goto remote_add_default; url_parse_local(zUrl, URL_PROMPT_PW, &x); db_begin_write(); db_multi_exec( "REPLACE INTO config(name, value, mtime)" " VALUES('sync-url:%q',%Q,now())", zName, x.canonical ); db_multi_exec( "REPLACE INTO config(name, value, mtime)" " VALUES('sync-pw:%q',obscure(%Q),now())", zName, x.passwd ); db_commit_transaction(); return; } if( strncmp(zArg, "delete", nArg)==0 ){ char *zName; if( g.argc!=4 ) usage("delete NAME"); zName = g.argv[3]; if( strcmp(zName,"default")==0 ) goto remote_delete_default; db_begin_write(); db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName); db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName); db_commit_transaction(); return; } if( sqlite3_strlike("http://%",zArg,0)==0 || sqlite3_strlike("https://%",zArg,0)==0 || sqlite3_strlike("ssh:%",zArg,0)==0 || sqlite3_strlike("file:%",zArg,0)==0 | > > > > | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | if( g.argc!=5 ) usage("add NAME URL"); memset(&x, 0, sizeof(x)); zName = g.argv[3]; zUrl = g.argv[4]; if( strcmp(zName,"default")==0 ) goto remote_add_default; url_parse_local(zUrl, URL_PROMPT_PW, &x); db_begin_write(); db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name, value, mtime)" " VALUES('sync-url:%q',%Q,now())", zName, x.canonical ); db_multi_exec( "REPLACE INTO config(name, value, mtime)" " VALUES('sync-pw:%q',obscure(%Q),now())", zName, x.passwd ); db_protect_pop(); db_commit_transaction(); return; } if( strncmp(zArg, "delete", nArg)==0 ){ char *zName; if( g.argc!=4 ) usage("delete NAME"); zName = g.argv[3]; if( strcmp(zName,"default")==0 ) goto remote_delete_default; db_begin_write(); db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName); db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName); db_protect_pop(); db_commit_transaction(); return; } if( sqlite3_strlike("http://%",zArg,0)==0 || sqlite3_strlike("https://%",zArg,0)==0 || sqlite3_strlike("ssh:%",zArg,0)==0 || sqlite3_strlike("file:%",zArg,0)==0 |
︙ | ︙ | |||
537 538 539 540 541 542 543 544 545 | if( file_delete(zDest) ){ fossil_fatal("unable to delete old copy of \"%s\"", zDest); } }else{ fossil_fatal("backup \"%s\" already exists", zDest); } } db_multi_exec("VACUUM repository INTO %Q", zDest); } | > | 543 544 545 546 547 548 549 550 551 552 | if( file_delete(zDest) ){ fossil_fatal("unable to delete old copy of \"%s\"", zDest); } }else{ fossil_fatal("backup \"%s\" already exists", zDest); } } db_unprotect(PROTECT_ALL); db_multi_exec("VACUUM repository INTO %Q", zDest); } |
Changes to src/tkt.c.
︙ | ︙ | |||
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | int ticket_change(const char *zUuid){ const char *zConfig; Th_FossilInit(TH_INIT_DEFAULT); Th_Store("uuid", zUuid); zConfig = ticket_change_code(); return Th_Eval(g.interp, 0, zConfig, -1); } /* ** Recreate the TICKET and TICKETCHNG tables. */ void ticket_create_table(int separateConnection){ char *zSql; db_multi_exec( "DROP TABLE IF EXISTS ticket;" "DROP TABLE IF EXISTS ticketchng;" ); zSql = ticket_table_schema(); if( separateConnection ){ if( db_transaction_nesting_depth() ) db_end_transaction(0); db_init_database(g.zRepositoryName, zSql, 0); }else{ db_multi_exec("%s", zSql/*safe-for-%s*/); } fossil_free(zSql); } /* ** Repopulate the TICKET and TICKETCHNG tables from scratch using all ** available ticket artifacts. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | int ticket_change(const char *zUuid){ const char *zConfig; Th_FossilInit(TH_INIT_DEFAULT); Th_Store("uuid", zUuid); zConfig = ticket_change_code(); return Th_Eval(g.interp, 0, zConfig, -1); } /* ** An authorizer function for the SQL used to initialize the ** schema for the ticketing system. Only allow CREATE TABLE and ** CREATE INDEX for tables whose names begin with "ticket" and ** changes to tables whose names begin with "ticket". */ static int ticket_schema_auth( void *pNErr, int eCode, const char *z0, const char *z1, const char *z2, const char *z3 ){ switch( eCode ){ case SQLITE_CREATE_TABLE: { if( sqlite3_stricmp(z2,"main")!=0 && sqlite3_stricmp(z2,"repository")!=0 ){ goto ticket_schema_error; } if( sqlite3_strnicmp(z0,"ticket",6)!=0 ){ goto ticket_schema_error; } break; } case SQLITE_CREATE_INDEX: { if( sqlite3_stricmp(z2,"main")!=0 && sqlite3_stricmp(z2,"repository")!=0 ){ goto ticket_schema_error; } if( sqlite3_strnicmp(z1,"ticket",6)!=0 ){ goto ticket_schema_error; } break; } case SQLITE_INSERT: case SQLITE_UPDATE: case SQLITE_DELETE: { if( sqlite3_stricmp(z2,"main")!=0 && sqlite3_stricmp(z2,"repository")!=0 ){ goto ticket_schema_error; } if( sqlite3_strnicmp(z0,"ticket",6)!=0 && sqlite3_strnicmp(z0,"sqlite_",7)!=0 ){ goto ticket_schema_error; } break; } case SQLITE_REINDEX: case SQLITE_TRANSACTION: case SQLITE_READ: { break; } default: { goto ticket_schema_error; } } return SQLITE_OK; ticket_schema_error: if( pNErr ) *(int*)pNErr = 1; return SQLITE_DENY; } /* ** Recreate the TICKET and TICKETCHNG tables. */ void ticket_create_table(int separateConnection){ char *zSql; db_multi_exec( "DROP TABLE IF EXISTS ticket;" "DROP TABLE IF EXISTS ticketchng;" ); zSql = ticket_table_schema(); db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema"); if( separateConnection ){ if( db_transaction_nesting_depth() ) db_end_transaction(0); db_init_database(g.zRepositoryName, zSql, 0); }else{ db_multi_exec("%s", zSql/*safe-for-%s*/); } db_clear_authorizer(); fossil_free(zSql); } /* ** Repopulate the TICKET and TICKETCHNG tables from scratch using all ** available ticket artifacts. */ |
︙ | ︙ |
Changes to src/undo.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | int new_exists; int old_exe; int new_exe; int new_link; int old_link; Blob current; Blob new; | | > > | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | int new_exists; int old_exe; int new_exe; int new_link; int old_link; Blob current; Blob new; zFullname = mprintf("%s%s", g.zLocalRoot, zPathname); old_link = db_column_int(&q, 3); new_exists = file_size(zFullname, RepoFILE)>=0; new_link = file_islink(0); if( new_exists ){ blob_read_from_file(¤t, zFullname, RepoFILE); new_exe = file_isexe(0,0); }else{ blob_zero(¤t); new_exe = 0; } blob_zero(&new); old_exists = db_column_int(&q, 1); old_exe = db_column_int(&q, 2); if( old_exists ){ db_ephemeral_blob(&q, 0, &new); } if( file_unsafe_in_tree_path(zFullname) ){ /* do nothign with this unsafe file */ }else if( old_exists ){ if( new_exists ){ fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname); }else{ fossil_print("NEW %s\n", zPathname); } if( new_exists && (new_link || old_link) ){ file_delete(zFullname); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
925 926 927 928 929 930 931 932 933 934 935 936 937 938 | db_multi_exec( "UPDATE OR REPLACE vfile" " SET pathname=origname, origname=NULL" " WHERE pathname=%Q AND origname!=pathname;" "DELETE FROM vfile WHERE pathname=%Q", zFile, zFile ); }else{ sqlite3_int64 mtime; int rvChnged = 0; int rvPerm = manifest_file_mperm(pRvFile); /* Determine if reverted-to file is different than checked out file. */ if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){ | > > | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | db_multi_exec( "UPDATE OR REPLACE vfile" " SET pathname=origname, origname=NULL" " WHERE pathname=%Q AND origname!=pathname;" "DELETE FROM vfile WHERE pathname=%Q", zFile, zFile ); }else if( file_unsafe_in_tree_path(zFull) ){ /* Ignore this file */ }else{ sqlite3_int64 mtime; int rvChnged = 0; int rvPerm = manifest_file_mperm(pRvFile); /* Determine if reverted-to file is different than checked out file. */ if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){ |
︙ | ︙ |
Changes to src/url.c.
︙ | ︙ | |||
48 49 50 51 52 53 54 | struct UrlData { int isFile; /* True if a "file:" url */ int isHttps; /* True if a "https:" url */ int isSsh; /* True if an "ssh:" url */ int isAlias; /* Input URL was an alias */ char *name; /* Hostname for http: or filename for file: */ char *hostname; /* The HOST: parameter on http headers */ | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | struct UrlData { int isFile; /* True if a "file:" url */ int isHttps; /* True if a "https:" url */ int isSsh; /* True if an "ssh:" url */ int isAlias; /* Input URL was an alias */ char *name; /* Hostname for http: or filename for file: */ char *hostname; /* The HOST: parameter on http headers */ const char *protocol; /* "http" or "https" or "ssh" or "file" */ int port; /* TCP port number for http: or https: */ int dfltPort; /* The default port for the given protocol */ char *path; /* Pathname for http: */ char *user; /* User id for http: */ char *passwd; /* Password for http: */ char *canonical; /* Canonical representation of the URL */ char *proxyAuth; /* Proxy-Authorizer: string */ |
︙ | ︙ | |||
74 75 76 77 78 79 80 | ** last-sync-url setting using last-sync-pw as the password. Store ** the parser results in the pUrlData object. Populate members of pUrlData ** as follows: ** ** isFile True if FILE: ** isHttps True if HTTPS: ** isSsh True if SSH: | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ** last-sync-url setting using last-sync-pw as the password. Store ** the parser results in the pUrlData object. Populate members of pUrlData ** as follows: ** ** isFile True if FILE: ** isHttps True if HTTPS: ** isSsh True if SSH: ** protocol "http" or "https" or "file" or "ssh" ** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** port TCP port number for HTTP or HTTPS. ** dfltPort Default TCP port number (80 or 443). ** path Path name for HTTP or HTTPS. ** user Userid. ** passwd Password. ** hostname HOST:PORT or just HOST if port is the default. |
︙ | ︙ | |||
303 304 305 306 307 308 309 | ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password ** form last-sync-pw. ** ** g.url.isFile True if FILE: ** g.url.isHttps True if HTTPS: ** g.url.isSsh True if SSH: | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password ** form last-sync-pw. ** ** g.url.isFile True if FILE: ** g.url.isHttps True if HTTPS: ** g.url.isSsh True if SSH: ** g.url.protocol "http" or "https" or "file" or "ssh" ** g.url.name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** g.url.port TCP port number for HTTP or HTTPS. ** g.url.dfltPort Default TCP port number (80 or 443). ** g.url.path Path name for HTTP or HTTPS. ** g.url.user Userid. ** g.url.passwd Password. ** g.url.hostname HOST:PORT or just HOST if port is the default. |
︙ | ︙ |
Changes to src/user.c.
︙ | ︙ | |||
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | zPrompt = mprintf("New password for %s: ", g.argv[3]); prompt_for_password(zPrompt, &pw, 1); } if( blob_size(&pw)==0 ){ fossil_print("password unchanged\n"); }else{ char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d", zSecret, uid); free(zSecret); } }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){ int uid; if( g.argc!=4 && g.argc!=5 ){ usage("capabilities USERNAME ?PERMISSIONS?"); } uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]); if( uid==0 ){ fossil_fatal("no such user: %s", g.argv[3]); } if( g.argc==5 ){ db_multi_exec( "UPDATE user SET cap=%Q, mtime=now() WHERE uid=%d", g.argv[4], uid ); } fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); }else{ fossil_fatal("user subcommand should be one of: " "capabilities default list new password"); } } | > > > > | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | zPrompt = mprintf("New password for %s: ", g.argv[3]); prompt_for_password(zPrompt, &pw, 1); } if( blob_size(&pw)==0 ){ fossil_print("password unchanged\n"); }else{ char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); db_unprotect(PROTECT_USER); db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d", zSecret, uid); db_protect_pop(); free(zSecret); } }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){ int uid; if( g.argc!=4 && g.argc!=5 ){ usage("capabilities USERNAME ?PERMISSIONS?"); } uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]); if( uid==0 ){ fossil_fatal("no such user: %s", g.argv[3]); } if( g.argc==5 ){ db_unprotect(PROTECT_USER); db_multi_exec( "UPDATE user SET cap=%Q, mtime=now() WHERE uid=%d", g.argv[4], uid ); db_protect_pop(); } fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); }else{ fossil_fatal("user subcommand should be one of: " "capabilities default list new password"); } } |
︙ | ︙ | |||
571 572 573 574 575 576 577 578 579 580 581 582 583 584 | ** has are unchanged. */ void user_hash_passwords_cmd(void){ if( g.argc!=3 ) usage("REPOSITORY"); db_open_repository(g.argv[2]); sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0, sha1_shared_secret_sql_function, 0, 0); db_multi_exec( "UPDATE user SET pw=shared_secret(pw,login), mtime=now()" " WHERE length(pw)>0 AND length(pw)!=40" ); } /* | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | ** has are unchanged. */ void user_hash_passwords_cmd(void){ if( g.argc!=3 ) usage("REPOSITORY"); db_open_repository(g.argv[2]); sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0, sha1_shared_secret_sql_function, 0, 0); db_unprotect(PROTECT_ALL); db_multi_exec( "UPDATE user SET pw=shared_secret(pw,login), mtime=now()" " WHERE length(pw)>0 AND length(pw)!=40" ); } /* |
︙ | ︙ |
Changes to src/vfile.c.
︙ | ︙ | |||
311 312 313 314 315 316 317 318 319 320 321 322 323 324 | const char *zName; id = db_column_int(&q, 0); zName = db_column_text(&q, 1); rid = db_column_int(&q, 2); isExe = db_column_int(&q, 3); isLink = db_column_int(&q, 4); content_get(rid, &content); if( file_is_the_same(&content, zName) ){ blob_reset(&content); if( file_setexe(zName, isExe) ){ db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName, RepoFILE), id); } | > > > | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | const char *zName; id = db_column_int(&q, 0); zName = db_column_text(&q, 1); rid = db_column_int(&q, 2); isExe = db_column_int(&q, 3); isLink = db_column_int(&q, 4); if( file_unsafe_in_tree_path(zName) ){ continue; } content_get(rid, &content); if( file_is_the_same(&content, zName) ){ blob_reset(&content); if( file_setexe(zName, isExe) ){ db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName, RepoFILE), id); } |
︙ | ︙ |
Changes to src/xfer.c.
︙ | ︙ | |||
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 | ); while( db_step(&q)==SQLITE_ROW ){ int x = db_column_int(&q,3); const char *zName = db_column_text(&q,4); if( db_column_int64(&q,1)<=iNow-maxAge || !is_a_leaf(x) ){ /* check-in locks expire after maxAge seconds, or when the ** check-in is no longer a leaf */ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); continue; } if( fossil_strcmp(zName+8, blob_str(&xfer.aToken[2]))==0 ){ const char *zClientId = db_column_text(&q, 2); const char *zLogin = db_column_text(&q,0); sqlite3_int64 mtime = db_column_int64(&q, 1); if( fossil_strcmp(zClientId, blob_str(&xfer.aToken[3]))!=0 ){ @ pragma ci-lock-fail %F(zLogin) %lld(mtime) } seenFault = 1; } } db_finalize(&q); if( !seenFault ){ db_multi_exec( "REPLACE INTO config(name,value,mtime)" "VALUES('ci-lock-%q',json_object('login',%Q,'clientid',%Q),now())", blob_str(&xfer.aToken[2]), g.zLogin, blob_str(&xfer.aToken[3]) ); } if( db_get_boolean("forbid-delta-manifests",0) ){ @ pragma avoid-delta-manifests } } /* pragma ci-unlock CLIENT-ID ** ** Remove any locks previously held by CLIENT-ID. Clients send this ** pragma with their own ID whenever they know that they no longer ** have any commits pending. */ if( blob_eq(&xfer.aToken[1], "ci-unlock") && xfer.nToken==3 && blob_is_hname(&xfer.aToken[2]) ){ db_multi_exec( "DELETE FROM config" " WHERE name GLOB 'ci-lock-*'" " AND json_extract(value,'$.clientid')=%Q", blob_str(&xfer.aToken[2]) ); } }else /* Unknown message */ { | > > > > > > | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 | ); while( db_step(&q)==SQLITE_ROW ){ int x = db_column_int(&q,3); const char *zName = db_column_text(&q,4); if( db_column_int64(&q,1)<=iNow-maxAge || !is_a_leaf(x) ){ /* check-in locks expire after maxAge seconds, or when the ** check-in is no longer a leaf */ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name=%Q", zName); db_protect_pop(); continue; } if( fossil_strcmp(zName+8, blob_str(&xfer.aToken[2]))==0 ){ const char *zClientId = db_column_text(&q, 2); const char *zLogin = db_column_text(&q,0); sqlite3_int64 mtime = db_column_int64(&q, 1); if( fossil_strcmp(zClientId, blob_str(&xfer.aToken[3]))!=0 ){ @ pragma ci-lock-fail %F(zLogin) %lld(mtime) } seenFault = 1; } } db_finalize(&q); if( !seenFault ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "REPLACE INTO config(name,value,mtime)" "VALUES('ci-lock-%q',json_object('login',%Q,'clientid',%Q),now())", blob_str(&xfer.aToken[2]), g.zLogin, blob_str(&xfer.aToken[3]) ); db_protect_pop(); } if( db_get_boolean("forbid-delta-manifests",0) ){ @ pragma avoid-delta-manifests } } /* pragma ci-unlock CLIENT-ID ** ** Remove any locks previously held by CLIENT-ID. Clients send this ** pragma with their own ID whenever they know that they no longer ** have any commits pending. */ if( blob_eq(&xfer.aToken[1], "ci-unlock") && xfer.nToken==3 && blob_is_hname(&xfer.aToken[2]) ){ db_unprotect(PROTECT_CONFIG); db_multi_exec( "DELETE FROM config" " WHERE name GLOB 'ci-lock-*'" " AND json_extract(value,'$.clientid')=%Q", blob_str(&xfer.aToken[2]) ); db_protect_pop(); } }else /* Unknown message */ { |
︙ | ︙ |
Added test/reserved-names.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | # # Copyright (c) 2020 D. Richard Hipp # # This program is free software; you can redistribute it and/or # modify it under the terms of the Simplified BSD License (also # known as the "2-Clause License" or "FreeBSD License".) # # This program is distributed in the hope that it will be useful, # but without any warranty; without even the implied warranty of # merchantability or fitness for a particular purpose. # # Author contact information: # drh@hwaci.com # http://www.hwaci.com/drh/ # ############################################################################ # # Tests for reserved names. # test_setup ############################################################################### set reserved_names_tests [list \ {0 {}} \ {0 a.fslckout} \ {1 .fslckout} \ {1 .FSlckOUT} \ {2 a/.fslckout} \ {0 .fslckout/b} \ {0 fslckout} \ {0 .fslckoutx} \ {1 _FOSSIL_} \ {0 _FOSSIL} \ {0 FOSSIL_} \ {0 FOSSIL_} \ {0 a_FOSSIL_} \ {0 _FOSSIL__} \ {0 __FOSSIL__} \ {0 __FOssIL__} \ {0 _FOSSIL_/a} \ {2 a/_FOSSIL_} \ {2 _FOSSIL_/c/.fslckout} \ {2 _FOSSIL_/c/.fslckout/_FOSSIL_} \ {0 _FOSSIL_/c/.fslckout/._FOSSIL_t} \ {0 _FOSSIL_/c/.fslckout/t._FOSSIL_} \ {0 a} \ {0 a/b} \ {0 a/b/c} \ {0 a/b/c/} \ {0 a/_FOSSIL/} \ {0 a/fslckout/} \ {0 a/_fslckout/} \ {0 _FOSSIL-wal} \ {0 _FOSSIL-shm} \ {0 _FOSSIL-journal} \ {0 _FOSSIL_-wal/a} \ {0 _FOSSIL_-shm/a} \ {0 _FOSSIL_-journal/a} \ {1 _FOSSIL_-wal} \ {1 _FOSSIL_-shm} \ {1 _FOSSIL_-journal} \ {2 a/_FOSSIL_-wal} \ {2 a/_FOSSIL_-shm} \ {2 a/_FOSSIL_-journal} \ {0 .fslckout-wal/a} \ {0 .fslckout-shm/a} \ {0 .fslckout-journal/a} \ {1 .fslckout-wal} \ {1 .fslckout-shm} \ {1 .fslckout-journal} \ {2 a/.fslckout-wal} \ {2 a/.fslckout-shm} \ {2 a/.fslckout-journal} \ ] ############################################################################### set testNo 0 foreach reserved_names_test $reserved_names_tests { incr testNo set reserved_result [lindex $reserved_names_test 0] set reserved_name [lindex $reserved_names_test 1] fossil test-is-reserved-name $reserved_name test reserved-result-$testNo { [lindex [normalize_result] 0] eq $reserved_result } test reserved-name-$testNo { [lindex [normalize_result] 1] eq $reserved_name } fossil test-is-reserved-name [string toupper $reserved_name] test reserved-result-upper-$testNo { [lindex [normalize_result] 0] eq $reserved_result } test reserved-name-upper-$testNo { [lindex [normalize_result] 1] eq [string toupper $reserved_name] } fossil test-is-reserved-name [string tolower $reserved_name] test reserved-result-lower-$testNo { [lindex [normalize_result] 0] eq $reserved_result } test reserved-name-lower-$testNo { [lindex [normalize_result] 1] eq [string tolower $reserved_name] } } ############################################################################### test_cleanup |