Fossil SCM

Enhancements to SEE integration.

mistachkin 2023-05-18 21:15 trunk
Commit d72ab72962fbd17d40e58bd2445c0d8593838bcc26bf6b3e26c0e12b0b13b2c1
+369 -34
--- src/db.c
+++ src/db.c
@@ -31,25 +31,57 @@
3131
*/
3232
#include "config.h"
3333
#if defined(_WIN32)
3434
# if USE_SEE
3535
# include <windows.h>
36
+# define GETPID (int)GetCurrentProcessId
3637
# endif
3738
#else
3839
# include <pwd.h>
40
+# if USE_SEE
41
+# define GETPID getpid
42
+# endif
3943
#endif
4044
#if USE_SEE && !defined(SQLITE_HAS_CODEC)
4145
# define SQLITE_HAS_CODEC
46
+#endif
47
+#if USE_SEE && defined(__linux__)
48
+# include <sys/uio.h>
4249
#endif
4350
#include <sqlite3.h>
4451
#include <sys/types.h>
4552
#include <sys/stat.h>
4653
#include <unistd.h>
4754
#include <time.h>
55
+
56
+/* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
57
+#if USE_SEE
58
+#if defined(_WIN32)
59
+typedef DWORD PID_T;
60
+#else
61
+typedef pid_t PID_T;
62
+#endif
63
+#endif
64
+
4865
#include "db.h"
4966
5067
#if INTERFACE
68
+/*
69
+** Type definitions used for handling the saved encryption key for SEE.
70
+*/
71
+#if !defined(_WIN32)
72
+typedef void *LPVOID;
73
+typedef size_t SIZE_T;
74
+#endif
75
+
76
+/*
77
+** Operations for db_maybe_handle_saved_encryption_key_for_process, et al.
78
+*/
79
+#define SEE_KEY_READ ((int)0)
80
+#define SEE_KEY_WRITE ((int)1)
81
+#define SEE_KEY_ZERO ((int)2)
82
+
5183
/*
5284
** An single SQL statement is represented as an instance of the following
5385
** structure.
5486
*/
5587
struct Stmt {
@@ -1539,11 +1571,30 @@
15391571
static char *zSavedKey = 0;
15401572
15411573
/*
15421574
** This is the size of the saved database encryption key, in bytes.
15431575
*/
1544
-size_t savedKeySize = 0;
1576
+static size_t savedKeySize = 0;
1577
+
1578
+/*
1579
+** This function returns non-zero if there is a saved database encryption
1580
+** key available.
1581
+*/
1582
+int db_have_saved_encryption_key(){
1583
+ return db_is_valid_saved_encryption_key(zSavedKey, savedKeySize);
1584
+}
1585
+
1586
+/*
1587
+** This function returns non-zero if the specified saved database encryption
1588
+** key is valid.
1589
+*/
1590
+int db_is_valid_saved_encryption_key(const char *p, size_t n){
1591
+ if( p==0 ) return 0;
1592
+ if( n==0 ) return 0;
1593
+ if( p[0]==0 ) return 0;
1594
+ return 1;
1595
+}
15451596
15461597
/*
15471598
** This function returns the saved database encryption key -OR- zero if
15481599
** no database encryption key is saved.
15491600
*/
@@ -1556,10 +1607,36 @@
15561607
** -OR- zero if no database encryption key is saved.
15571608
*/
15581609
size_t db_get_saved_encryption_key_size(){
15591610
return savedKeySize;
15601611
}
1612
+
1613
+/*
1614
+** This function arranges for the saved database encryption key buffer
1615
+** to be allocated and then sets up the environment variable to allow
1616
+** a child process to initialize it with the actual database encryption
1617
+** key.
1618
+*/
1619
+void db_setup_for_saved_encryption_key(){
1620
+ void *p = NULL;
1621
+ size_t n = 0;
1622
+ size_t pageSize = 0;
1623
+ Blob pidKey;
1624
+
1625
+ assert( !db_have_saved_encryption_key() );
1626
+ db_unsave_encryption_key();
1627
+ fossil_get_page_size(&pageSize);
1628
+ assert( pageSize>0 );
1629
+ p = fossil_secure_alloc_page(&n);
1630
+ assert( p!=NULL );
1631
+ assert( n==pageSize );
1632
+ blob_zero(&pidKey);
1633
+ blob_appendf(&pidKey, "%lu:%p:%u", (unsigned long)GETPID(), p, n);
1634
+ fossil_setenv("FOSSIL_SEE_PID_KEY", blob_str(&pidKey));
1635
+ zSavedKey = p;
1636
+ savedKeySize = n;
1637
+}
15611638
15621639
/*
15631640
** This function arranges for the database encryption key to be securely
15641641
** saved in non-pagable memory (on platforms where this is possible).
15651642
*/
@@ -1569,10 +1646,11 @@
15691646
void *p = NULL;
15701647
size_t n = 0;
15711648
size_t pageSize = 0;
15721649
size_t blobSize = 0;
15731650
1651
+ assert( !db_have_saved_encryption_key() );
15741652
blobSize = blob_size(pKey);
15751653
if( blobSize==0 ) return;
15761654
fossil_get_page_size(&pageSize);
15771655
assert( pageSize>0 );
15781656
if( blobSize>pageSize ){
@@ -1599,11 +1677,11 @@
15991677
16001678
/*
16011679
** This function sets the saved database encryption key to the specified
16021680
** string value, allocating or freeing the underlying memory if needed.
16031681
*/
1604
-void db_set_saved_encryption_key(
1682
+static void db_set_saved_encryption_key(
16051683
Blob *pKey
16061684
){
16071685
if( zSavedKey!=NULL ){
16081686
size_t blobSize = blob_size(pKey);
16091687
if( blobSize==0 ){
@@ -1619,25 +1697,213 @@
16191697
}else{
16201698
db_save_encryption_key(pKey);
16211699
}
16221700
}
16231701
1702
+/*
1703
+** WEBPAGE: setseekey
1704
+**
1705
+** Sets the sets the saved database encryption key to one that gets passed
1706
+** via the "key" query string parameter. If the saved database encryption
1707
+** key has already been set, does nothing. This web page does not produce
1708
+** any output on success or failure.
1709
+**
1710
+** Query parameters:
1711
+**
1712
+** key The string to set as the saved database encryption
1713
+** key.
1714
+*/
1715
+void db_set_see_key_page(void){
1716
+ Blob key;
1717
+ const char *zKey;
1718
+ if( db_have_saved_encryption_key() ){
1719
+ fossil_errorlog("SEE: encryption key was already set\n");
1720
+ return;
1721
+ }
1722
+ zKey = P("key");
1723
+ blob_init(&key, 0, 0);
1724
+ if( zKey!=0 ){
1725
+ PID_T processId;
1726
+ blob_set(&key, zKey);
1727
+ db_set_saved_encryption_key(&key);
1728
+ processId = db_maybe_handle_saved_encryption_key_for_process(
1729
+ SEE_KEY_WRITE
1730
+ );
1731
+ fossil_errorlog("SEE: set encryption key for process %lu, length %u\n",
1732
+ (unsigned long)processId, blob_size(&key));
1733
+ }else{
1734
+ fossil_errorlog("SEE: no encryption key specified\n");
1735
+ }
1736
+ blob_reset(&key);
1737
+}
1738
+
1739
+/*
1740
+** WEBPAGE: unsetseekey
1741
+**
1742
+** Unsets the saved database encryption key to zeros. If the saved database
1743
+** encryption key has already been set, does nothing. This web page does not
1744
+** produce any output on success or failure.
1745
+*/
1746
+void db_unset_see_key_page(void){
1747
+ PID_T processId;
1748
+ login_check_credentials();
1749
+ if( !g.perm.Setup ){ login_needed(0); return; }
1750
+ processId = db_maybe_handle_saved_encryption_key_for_process(
1751
+ SEE_KEY_ZERO
1752
+ );
1753
+ fossil_errorlog("SEE: unset encryption key for process %lu\n",
1754
+ (unsigned long)processId);
1755
+}
1756
+
1757
+/*
1758
+** This function reads the saved database encryption key from the
1759
+** specified Fossil parent process. This is only necessary (or
1760
+** functional) on Windows or Linux.
1761
+*/
1762
+static void db_read_saved_encryption_key_from_process(
1763
+ PID_T processId, /* Identifier for Fossil parent process. */
1764
+ LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
1765
+ SIZE_T nSize /* Size of saved key buffer in the parent process. */
1766
+){
1767
+ void *p = NULL;
1768
+ size_t n = 0;
1769
+ size_t pageSize = 0;
1770
+
1771
+ fossil_get_page_size(&pageSize);
1772
+ assert( pageSize>0 );
1773
+ if( nSize>pageSize ){
1774
+ fossil_panic("key too large: %u versus %u", nSize, pageSize);
1775
+ }
1776
+ p = fossil_secure_alloc_page(&n);
1777
+ assert( p!=NULL );
1778
+ assert( n==pageSize );
1779
+ assert( n>=nSize );
1780
+ {
1781
+#if defined(_WIN32)
1782
+ HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processId);
1783
+ if( hProcess!=NULL ){
1784
+ SIZE_T nRead = 0;
1785
+ if( ReadProcessMemory(hProcess, pAddress, p, nSize, &nRead) ){
1786
+ CloseHandle(hProcess);
1787
+ if( nRead==nSize ){
1788
+ db_unsave_encryption_key();
1789
+ zSavedKey = p;
1790
+ savedKeySize = n;
1791
+ }else{
1792
+ fossil_secure_free_page(p, n);
1793
+ fossil_panic("bad size read, %u out of %u bytes at %p from pid %lu",
1794
+ nRead, nSize, pAddress, processId);
1795
+ }
1796
+ }else{
1797
+ CloseHandle(hProcess);
1798
+ fossil_secure_free_page(p, n);
1799
+ fossil_panic("failed read, %u bytes at %p from pid %lu: %lu", nSize,
1800
+ pAddress, processId, GetLastError());
1801
+ }
1802
+ }else{
1803
+ fossil_secure_free_page(p, n);
1804
+ fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1805
+ }
1806
+#elif defined(__linux__)
1807
+ ssize_t nRead;
1808
+ struct iovec liov = {0};
1809
+ struct iovec riov = {0};
1810
+ liov.iov_base = p;
1811
+ liov.iov_len = n;
1812
+ riov.iov_base = pAddress;
1813
+ riov.iov_len = nSize;
1814
+ nRead = process_vm_readv(processId, &liov, 1, &riov, 1, 0);
1815
+ if( nRead==nSize ){
1816
+ db_unsave_encryption_key();
1817
+ zSavedKey = p;
1818
+ savedKeySize = n;
1819
+ }else{
1820
+ fossil_secure_free_page(p, n);
1821
+ fossil_panic("bad size read, %zd out of %zu bytes at %p from pid %lu",
1822
+ nRead, nSize, pAddress, (unsigned long)processId);
1823
+ }
1824
+#else
1825
+ fossil_secure_free_page(p, n);
1826
+ fossil_panic("db_read_saved_encryption_key_from_process unsupported");
1827
+#endif
1828
+ }
1829
+}
1830
+
1831
+/*
1832
+** This function writes the saved database encryption key into the
1833
+** specified Fossil parent process. This is only necessary (or
1834
+** functional) on Windows or Linux.
1835
+*/
1836
+static void db_write_saved_encryption_key_to_process(
1837
+ PID_T processId, /* Identifier for Fossil parent process. */
1838
+ LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
1839
+ SIZE_T nSize /* Size of saved key buffer in the parent process. */
1840
+){
1841
+ void *p = db_get_saved_encryption_key();
1842
+ size_t n = db_get_saved_encryption_key_size();
1843
+ size_t pageSize = 0;
1844
+
1845
+ fossil_get_page_size(&pageSize);
1846
+ assert( pageSize>0 );
1847
+ if( nSize>pageSize ){
1848
+ fossil_panic("key too large: %u versus %u", nSize, pageSize);
1849
+ }
1850
+ assert( p!=NULL );
1851
+ assert( n==pageSize );
1852
+ assert( n>=nSize );
1853
+ {
16241854
#if defined(_WIN32)
1855
+ HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
1856
+ FALSE, processId);
1857
+ if( hProcess!=NULL ){
1858
+ SIZE_T nWrite = 0;
1859
+ if( WriteProcessMemory(hProcess, pAddress, p, nSize, &nWrite) ){
1860
+ CloseHandle(hProcess);
1861
+ if( nWrite!=nSize ){
1862
+ fossil_panic("bad size write, %u out of %u bytes at %p from pid %lu",
1863
+ nRead, nSize, pAddress, processId);
1864
+ }
1865
+ }else{
1866
+ CloseHandle(hProcess);
1867
+ fossil_panic("failed write, %u bytes at %p from pid %lu: %lu", nSize,
1868
+ pAddress, processId, GetLastError());
1869
+ }
1870
+ }else{
1871
+ fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1872
+ }
1873
+#elif defined(__linux__)
1874
+ ssize_t nWrite;
1875
+ struct iovec liov = {0};
1876
+ struct iovec riov = {0};
1877
+ liov.iov_base = p;
1878
+ liov.iov_len = n;
1879
+ riov.iov_base = pAddress;
1880
+ riov.iov_len = nSize;
1881
+ nWrite = process_vm_writev(processId, &liov, 1, &riov, 1, 0);
1882
+ if( nWrite!=nSize ){
1883
+ fossil_panic("bad size write, %zd out of %zu bytes at %p from pid %lu",
1884
+ nWrite, nSize, pAddress, (unsigned long)processId);
1885
+ }
1886
+#else
1887
+ fossil_panic("db_write_saved_encryption_key_to_process unsupported");
1888
+#endif
1889
+ }
1890
+}
1891
+
16251892
/*
1626
-** This function sets the saved database encryption key to one that gets
1627
-** read from the specified Fossil parent process. This is only necessary
1628
-** (or functional) on Windows.
1893
+** This function zero the saved database encryption key in the specified
1894
+** Fossil parent process. This is only necessary (or functional) on
1895
+** Windows or Linux.
16291896
*/
1630
-void db_read_saved_encryption_key_from_process(
1631
- DWORD processId, /* Identifier for Fossil parent process. */
1897
+static void db_zero_saved_encryption_key_in_process(
1898
+ PID_T processId, /* Identifier for Fossil parent process. */
16321899
LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
16331900
SIZE_T nSize /* Size of saved key buffer in the parent process. */
16341901
){
16351902
void *p = NULL;
16361903
size_t n = 0;
16371904
size_t pageSize = 0;
1638
- HANDLE hProcess = NULL;
16391905
16401906
fossil_get_page_size(&pageSize);
16411907
assert( pageSize>0 );
16421908
if( nSize>pageSize ){
16431909
fossil_panic("key too large: %u versus %u", nSize, pageSize);
@@ -1644,42 +1910,66 @@
16441910
}
16451911
p = fossil_secure_alloc_page(&n);
16461912
assert( p!=NULL );
16471913
assert( n==pageSize );
16481914
assert( n>=nSize );
1649
- hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processId);
1650
- if( hProcess!=NULL ){
1651
- SIZE_T nRead = 0;
1652
- if( ReadProcessMemory(hProcess, pAddress, p, nSize, &nRead) ){
1653
- CloseHandle(hProcess);
1654
- if( nRead==nSize ){
1655
- db_unsave_encryption_key();
1656
- zSavedKey = p;
1657
- savedKeySize = n;
1658
- }else{
1659
- fossil_panic("bad size read, %u out of %u bytes at %p from pid %lu",
1660
- nRead, nSize, pAddress, processId);
1661
- }
1662
- }else{
1663
- CloseHandle(hProcess);
1664
- fossil_panic("failed read, %u bytes at %p from pid %lu: %lu", nSize,
1665
- pAddress, processId, GetLastError());
1666
- }
1667
- }else{
1668
- fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1915
+ {
1916
+#if defined(_WIN32)
1917
+ HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
1918
+ FALSE, processId);
1919
+ if( hProcess!=NULL ){
1920
+ SIZE_T nWrite = 0;
1921
+ if( WriteProcessMemory(hProcess, pAddress, p, nSize, &nWrite) ){
1922
+ CloseHandle(hProcess);
1923
+ fossil_secure_free_page(p, n);
1924
+ if( nWrite!=nSize ){
1925
+ fossil_panic("bad size zero, %u out of %u bytes at %p from pid %lu",
1926
+ nRead, nSize, pAddress, processId);
1927
+ }
1928
+ }else{
1929
+ CloseHandle(hProcess);
1930
+ fossil_secure_free_page(p, n);
1931
+ fossil_panic("failed zero, %u bytes at %p from pid %lu: %lu", nSize,
1932
+ pAddress, processId, GetLastError());
1933
+ }
1934
+ }else{
1935
+ fossil_secure_free_page(p, n);
1936
+ fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1937
+ }
1938
+#elif defined(__linux__)
1939
+ ssize_t nWrite;
1940
+ struct iovec liov = {0};
1941
+ struct iovec riov = {0};
1942
+ liov.iov_base = p;
1943
+ liov.iov_len = n;
1944
+ riov.iov_base = pAddress;
1945
+ riov.iov_len = nSize;
1946
+ nWrite = process_vm_writev(processId, &liov, 1, &riov, 1, 0);
1947
+ if( nWrite!=nSize ){
1948
+ fossil_secure_free_page(p, n);
1949
+ fossil_panic("bad size zero, %zd out of %zu bytes at %p from pid %lu",
1950
+ nWrite, nSize, pAddress, (unsigned long)processId);
1951
+ }
1952
+#else
1953
+ fossil_secure_free_page(p, n);
1954
+ fossil_panic("db_zero_saved_encryption_key_in_process unsupported");
1955
+#endif
16691956
}
16701957
}
16711958
16721959
/*
16731960
** This function evaluates the specified TH1 script and attempts to parse
16741961
** its result as a colon-delimited triplet containing a process identifier,
16751962
** address, and size (in bytes) of the database encryption key. This is
1676
-** only necessary (or functional) on Windows.
1963
+** only necessary (or functional) on Windows or Linux.
16771964
*/
1678
-void db_read_saved_encryption_key_from_process_via_th1(
1679
- const char *zConfig /* The TH1 script to evaluate. */
1965
+static PID_T db_handle_saved_encryption_key_for_process_via_th1(
1966
+ const char *zConfig, /* The TH1 script to evaluate. */
1967
+ int eType /* Non-zero to write key to parent process -OR-
1968
+ * zero to read it from the parent process. */
16801969
){
1970
+ PID_T processId = 0;
16811971
int rc;
16821972
char *zResult;
16831973
char *zPwd = file_getcwd(0, 0);
16841974
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_NEED_CONFIG | TH_INIT_NO_REPO);
16851975
rc = Th_Eval(g.interp, 0, zConfig, -1);
@@ -1686,20 +1976,65 @@
16861976
zResult = (char*)Th_GetResult(g.interp, 0);
16871977
if( rc!=TH_OK ){
16881978
fossil_fatal("script for pid key failed: %s", zResult);
16891979
}
16901980
if( zResult ){
1691
- DWORD processId = 0;
16921981
LPVOID pAddress = NULL;
16931982
SIZE_T nSize = 0;
16941983
parse_pid_key_value(zResult, &processId, &pAddress, &nSize);
1695
- db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
1984
+ if( eType==SEE_KEY_READ ){
1985
+ db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
1986
+ }else if( eType==SEE_KEY_WRITE ){
1987
+ db_write_saved_encryption_key_to_process(processId, pAddress, nSize);
1988
+ }else if( eType==SEE_KEY_ZERO ){
1989
+ db_zero_saved_encryption_key_in_process(processId, pAddress, nSize);
1990
+ }else{
1991
+ fossil_panic("unsupported SEE key operation %d", eType);
1992
+ }
16961993
}
16971994
file_chdir(zPwd, 0);
16981995
fossil_free(zPwd);
1996
+ return processId;
16991997
}
1700
-#endif /* defined(_WIN32) */
1998
+
1999
+/*
2000
+** This function sets the saved database encryption key to one that gets
2001
+** read from the specified Fossil parent process, if applicable. This is
2002
+** only necessary (or functional) on Windows or Linux.
2003
+*/
2004
+PID_T db_maybe_handle_saved_encryption_key_for_process(int eType){
2005
+ PID_T processId = 0;
2006
+ g.zPidKey = find_option("usepidkey",0,1);
2007
+ if( !g.zPidKey ){
2008
+ g.zPidKey = fossil_getenv("FOSSIL_SEE_PID_KEY");
2009
+ }
2010
+ if( g.zPidKey ){
2011
+ LPVOID pAddress = NULL;
2012
+ SIZE_T nSize = 0;
2013
+ parse_pid_key_value(g.zPidKey, &processId, &pAddress, &nSize);
2014
+ if( eType==SEE_KEY_READ ){
2015
+ db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
2016
+ }else if( eType==SEE_KEY_WRITE ){
2017
+ db_write_saved_encryption_key_to_process(processId, pAddress, nSize);
2018
+ }else if( eType==SEE_KEY_ZERO ){
2019
+ db_zero_saved_encryption_key_in_process(processId, pAddress, nSize);
2020
+ }else{
2021
+ fossil_panic("unsupported SEE key operation %d", eType);
2022
+ }
2023
+ }else{
2024
+ const char *zSeeDbConfig = find_option("seedbcfg",0,1);
2025
+ if( !zSeeDbConfig ){
2026
+ zSeeDbConfig = fossil_getenv("FOSSIL_SEE_DB_CONFIG");
2027
+ }
2028
+ if( zSeeDbConfig ){
2029
+ processId = db_handle_saved_encryption_key_for_process_via_th1(
2030
+ zSeeDbConfig, eType
2031
+ );
2032
+ }
2033
+ }
2034
+ return processId;
2035
+}
17012036
#endif /* USE_SEE */
17022037
17032038
/*
17042039
** If the database file zDbFile has a name that suggests that it is
17052040
** encrypted, then prompt for the database encryption key and return it
17062041
--- src/db.c
+++ src/db.c
@@ -31,25 +31,57 @@
31 */
32 #include "config.h"
33 #if defined(_WIN32)
34 # if USE_SEE
35 # include <windows.h>
 
36 # endif
37 #else
38 # include <pwd.h>
 
 
 
39 #endif
40 #if USE_SEE && !defined(SQLITE_HAS_CODEC)
41 # define SQLITE_HAS_CODEC
 
 
 
42 #endif
43 #include <sqlite3.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <time.h>
 
 
 
 
 
 
 
 
 
 
48 #include "db.h"
49
50 #if INTERFACE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51 /*
52 ** An single SQL statement is represented as an instance of the following
53 ** structure.
54 */
55 struct Stmt {
@@ -1539,11 +1571,30 @@
1539 static char *zSavedKey = 0;
1540
1541 /*
1542 ** This is the size of the saved database encryption key, in bytes.
1543 */
1544 size_t savedKeySize = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1545
1546 /*
1547 ** This function returns the saved database encryption key -OR- zero if
1548 ** no database encryption key is saved.
1549 */
@@ -1556,10 +1607,36 @@
1556 ** -OR- zero if no database encryption key is saved.
1557 */
1558 size_t db_get_saved_encryption_key_size(){
1559 return savedKeySize;
1560 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1561
1562 /*
1563 ** This function arranges for the database encryption key to be securely
1564 ** saved in non-pagable memory (on platforms where this is possible).
1565 */
@@ -1569,10 +1646,11 @@
1569 void *p = NULL;
1570 size_t n = 0;
1571 size_t pageSize = 0;
1572 size_t blobSize = 0;
1573
 
1574 blobSize = blob_size(pKey);
1575 if( blobSize==0 ) return;
1576 fossil_get_page_size(&pageSize);
1577 assert( pageSize>0 );
1578 if( blobSize>pageSize ){
@@ -1599,11 +1677,11 @@
1599
1600 /*
1601 ** This function sets the saved database encryption key to the specified
1602 ** string value, allocating or freeing the underlying memory if needed.
1603 */
1604 void db_set_saved_encryption_key(
1605 Blob *pKey
1606 ){
1607 if( zSavedKey!=NULL ){
1608 size_t blobSize = blob_size(pKey);
1609 if( blobSize==0 ){
@@ -1619,25 +1697,213 @@
1619 }else{
1620 db_save_encryption_key(pKey);
1621 }
1622 }
1623
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1624 #if defined(_WIN32)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1625 /*
1626 ** This function sets the saved database encryption key to one that gets
1627 ** read from the specified Fossil parent process. This is only necessary
1628 ** (or functional) on Windows.
1629 */
1630 void db_read_saved_encryption_key_from_process(
1631 DWORD processId, /* Identifier for Fossil parent process. */
1632 LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
1633 SIZE_T nSize /* Size of saved key buffer in the parent process. */
1634 ){
1635 void *p = NULL;
1636 size_t n = 0;
1637 size_t pageSize = 0;
1638 HANDLE hProcess = NULL;
1639
1640 fossil_get_page_size(&pageSize);
1641 assert( pageSize>0 );
1642 if( nSize>pageSize ){
1643 fossil_panic("key too large: %u versus %u", nSize, pageSize);
@@ -1644,42 +1910,66 @@
1644 }
1645 p = fossil_secure_alloc_page(&n);
1646 assert( p!=NULL );
1647 assert( n==pageSize );
1648 assert( n>=nSize );
1649 hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processId);
1650 if( hProcess!=NULL ){
1651 SIZE_T nRead = 0;
1652 if( ReadProcessMemory(hProcess, pAddress, p, nSize, &nRead) ){
1653 CloseHandle(hProcess);
1654 if( nRead==nSize ){
1655 db_unsave_encryption_key();
1656 zSavedKey = p;
1657 savedKeySize = n;
1658 }else{
1659 fossil_panic("bad size read, %u out of %u bytes at %p from pid %lu",
1660 nRead, nSize, pAddress, processId);
1661 }
1662 }else{
1663 CloseHandle(hProcess);
1664 fossil_panic("failed read, %u bytes at %p from pid %lu: %lu", nSize,
1665 pAddress, processId, GetLastError());
1666 }
1667 }else{
1668 fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1669 }
1670 }
1671
1672 /*
1673 ** This function evaluates the specified TH1 script and attempts to parse
1674 ** its result as a colon-delimited triplet containing a process identifier,
1675 ** address, and size (in bytes) of the database encryption key. This is
1676 ** only necessary (or functional) on Windows.
1677 */
1678 void db_read_saved_encryption_key_from_process_via_th1(
1679 const char *zConfig /* The TH1 script to evaluate. */
 
 
1680 ){
 
1681 int rc;
1682 char *zResult;
1683 char *zPwd = file_getcwd(0, 0);
1684 Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_NEED_CONFIG | TH_INIT_NO_REPO);
1685 rc = Th_Eval(g.interp, 0, zConfig, -1);
@@ -1686,20 +1976,65 @@
1686 zResult = (char*)Th_GetResult(g.interp, 0);
1687 if( rc!=TH_OK ){
1688 fossil_fatal("script for pid key failed: %s", zResult);
1689 }
1690 if( zResult ){
1691 DWORD processId = 0;
1692 LPVOID pAddress = NULL;
1693 SIZE_T nSize = 0;
1694 parse_pid_key_value(zResult, &processId, &pAddress, &nSize);
1695 db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
 
 
 
 
 
 
 
 
1696 }
1697 file_chdir(zPwd, 0);
1698 fossil_free(zPwd);
 
1699 }
1700 #endif /* defined(_WIN32) */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1701 #endif /* USE_SEE */
1702
1703 /*
1704 ** If the database file zDbFile has a name that suggests that it is
1705 ** encrypted, then prompt for the database encryption key and return it
1706
--- src/db.c
+++ src/db.c
@@ -31,25 +31,57 @@
31 */
32 #include "config.h"
33 #if defined(_WIN32)
34 # if USE_SEE
35 # include <windows.h>
36 # define GETPID (int)GetCurrentProcessId
37 # endif
38 #else
39 # include <pwd.h>
40 # if USE_SEE
41 # define GETPID getpid
42 # endif
43 #endif
44 #if USE_SEE && !defined(SQLITE_HAS_CODEC)
45 # define SQLITE_HAS_CODEC
46 #endif
47 #if USE_SEE && defined(__linux__)
48 # include <sys/uio.h>
49 #endif
50 #include <sqlite3.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <unistd.h>
54 #include <time.h>
55
56 /* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
57 #if USE_SEE
58 #if defined(_WIN32)
59 typedef DWORD PID_T;
60 #else
61 typedef pid_t PID_T;
62 #endif
63 #endif
64
65 #include "db.h"
66
67 #if INTERFACE
68 /*
69 ** Type definitions used for handling the saved encryption key for SEE.
70 */
71 #if !defined(_WIN32)
72 typedef void *LPVOID;
73 typedef size_t SIZE_T;
74 #endif
75
76 /*
77 ** Operations for db_maybe_handle_saved_encryption_key_for_process, et al.
78 */
79 #define SEE_KEY_READ ((int)0)
80 #define SEE_KEY_WRITE ((int)1)
81 #define SEE_KEY_ZERO ((int)2)
82
83 /*
84 ** An single SQL statement is represented as an instance of the following
85 ** structure.
86 */
87 struct Stmt {
@@ -1539,11 +1571,30 @@
1571 static char *zSavedKey = 0;
1572
1573 /*
1574 ** This is the size of the saved database encryption key, in bytes.
1575 */
1576 static size_t savedKeySize = 0;
1577
1578 /*
1579 ** This function returns non-zero if there is a saved database encryption
1580 ** key available.
1581 */
1582 int db_have_saved_encryption_key(){
1583 return db_is_valid_saved_encryption_key(zSavedKey, savedKeySize);
1584 }
1585
1586 /*
1587 ** This function returns non-zero if the specified saved database encryption
1588 ** key is valid.
1589 */
1590 int db_is_valid_saved_encryption_key(const char *p, size_t n){
1591 if( p==0 ) return 0;
1592 if( n==0 ) return 0;
1593 if( p[0]==0 ) return 0;
1594 return 1;
1595 }
1596
1597 /*
1598 ** This function returns the saved database encryption key -OR- zero if
1599 ** no database encryption key is saved.
1600 */
@@ -1556,10 +1607,36 @@
1607 ** -OR- zero if no database encryption key is saved.
1608 */
1609 size_t db_get_saved_encryption_key_size(){
1610 return savedKeySize;
1611 }
1612
1613 /*
1614 ** This function arranges for the saved database encryption key buffer
1615 ** to be allocated and then sets up the environment variable to allow
1616 ** a child process to initialize it with the actual database encryption
1617 ** key.
1618 */
1619 void db_setup_for_saved_encryption_key(){
1620 void *p = NULL;
1621 size_t n = 0;
1622 size_t pageSize = 0;
1623 Blob pidKey;
1624
1625 assert( !db_have_saved_encryption_key() );
1626 db_unsave_encryption_key();
1627 fossil_get_page_size(&pageSize);
1628 assert( pageSize>0 );
1629 p = fossil_secure_alloc_page(&n);
1630 assert( p!=NULL );
1631 assert( n==pageSize );
1632 blob_zero(&pidKey);
1633 blob_appendf(&pidKey, "%lu:%p:%u", (unsigned long)GETPID(), p, n);
1634 fossil_setenv("FOSSIL_SEE_PID_KEY", blob_str(&pidKey));
1635 zSavedKey = p;
1636 savedKeySize = n;
1637 }
1638
1639 /*
1640 ** This function arranges for the database encryption key to be securely
1641 ** saved in non-pagable memory (on platforms where this is possible).
1642 */
@@ -1569,10 +1646,11 @@
1646 void *p = NULL;
1647 size_t n = 0;
1648 size_t pageSize = 0;
1649 size_t blobSize = 0;
1650
1651 assert( !db_have_saved_encryption_key() );
1652 blobSize = blob_size(pKey);
1653 if( blobSize==0 ) return;
1654 fossil_get_page_size(&pageSize);
1655 assert( pageSize>0 );
1656 if( blobSize>pageSize ){
@@ -1599,11 +1677,11 @@
1677
1678 /*
1679 ** This function sets the saved database encryption key to the specified
1680 ** string value, allocating or freeing the underlying memory if needed.
1681 */
1682 static void db_set_saved_encryption_key(
1683 Blob *pKey
1684 ){
1685 if( zSavedKey!=NULL ){
1686 size_t blobSize = blob_size(pKey);
1687 if( blobSize==0 ){
@@ -1619,25 +1697,213 @@
1697 }else{
1698 db_save_encryption_key(pKey);
1699 }
1700 }
1701
1702 /*
1703 ** WEBPAGE: setseekey
1704 **
1705 ** Sets the sets the saved database encryption key to one that gets passed
1706 ** via the "key" query string parameter. If the saved database encryption
1707 ** key has already been set, does nothing. This web page does not produce
1708 ** any output on success or failure.
1709 **
1710 ** Query parameters:
1711 **
1712 ** key The string to set as the saved database encryption
1713 ** key.
1714 */
1715 void db_set_see_key_page(void){
1716 Blob key;
1717 const char *zKey;
1718 if( db_have_saved_encryption_key() ){
1719 fossil_errorlog("SEE: encryption key was already set\n");
1720 return;
1721 }
1722 zKey = P("key");
1723 blob_init(&key, 0, 0);
1724 if( zKey!=0 ){
1725 PID_T processId;
1726 blob_set(&key, zKey);
1727 db_set_saved_encryption_key(&key);
1728 processId = db_maybe_handle_saved_encryption_key_for_process(
1729 SEE_KEY_WRITE
1730 );
1731 fossil_errorlog("SEE: set encryption key for process %lu, length %u\n",
1732 (unsigned long)processId, blob_size(&key));
1733 }else{
1734 fossil_errorlog("SEE: no encryption key specified\n");
1735 }
1736 blob_reset(&key);
1737 }
1738
1739 /*
1740 ** WEBPAGE: unsetseekey
1741 **
1742 ** Unsets the saved database encryption key to zeros. If the saved database
1743 ** encryption key has already been set, does nothing. This web page does not
1744 ** produce any output on success or failure.
1745 */
1746 void db_unset_see_key_page(void){
1747 PID_T processId;
1748 login_check_credentials();
1749 if( !g.perm.Setup ){ login_needed(0); return; }
1750 processId = db_maybe_handle_saved_encryption_key_for_process(
1751 SEE_KEY_ZERO
1752 );
1753 fossil_errorlog("SEE: unset encryption key for process %lu\n",
1754 (unsigned long)processId);
1755 }
1756
1757 /*
1758 ** This function reads the saved database encryption key from the
1759 ** specified Fossil parent process. This is only necessary (or
1760 ** functional) on Windows or Linux.
1761 */
1762 static void db_read_saved_encryption_key_from_process(
1763 PID_T processId, /* Identifier for Fossil parent process. */
1764 LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
1765 SIZE_T nSize /* Size of saved key buffer in the parent process. */
1766 ){
1767 void *p = NULL;
1768 size_t n = 0;
1769 size_t pageSize = 0;
1770
1771 fossil_get_page_size(&pageSize);
1772 assert( pageSize>0 );
1773 if( nSize>pageSize ){
1774 fossil_panic("key too large: %u versus %u", nSize, pageSize);
1775 }
1776 p = fossil_secure_alloc_page(&n);
1777 assert( p!=NULL );
1778 assert( n==pageSize );
1779 assert( n>=nSize );
1780 {
1781 #if defined(_WIN32)
1782 HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processId);
1783 if( hProcess!=NULL ){
1784 SIZE_T nRead = 0;
1785 if( ReadProcessMemory(hProcess, pAddress, p, nSize, &nRead) ){
1786 CloseHandle(hProcess);
1787 if( nRead==nSize ){
1788 db_unsave_encryption_key();
1789 zSavedKey = p;
1790 savedKeySize = n;
1791 }else{
1792 fossil_secure_free_page(p, n);
1793 fossil_panic("bad size read, %u out of %u bytes at %p from pid %lu",
1794 nRead, nSize, pAddress, processId);
1795 }
1796 }else{
1797 CloseHandle(hProcess);
1798 fossil_secure_free_page(p, n);
1799 fossil_panic("failed read, %u bytes at %p from pid %lu: %lu", nSize,
1800 pAddress, processId, GetLastError());
1801 }
1802 }else{
1803 fossil_secure_free_page(p, n);
1804 fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1805 }
1806 #elif defined(__linux__)
1807 ssize_t nRead;
1808 struct iovec liov = {0};
1809 struct iovec riov = {0};
1810 liov.iov_base = p;
1811 liov.iov_len = n;
1812 riov.iov_base = pAddress;
1813 riov.iov_len = nSize;
1814 nRead = process_vm_readv(processId, &liov, 1, &riov, 1, 0);
1815 if( nRead==nSize ){
1816 db_unsave_encryption_key();
1817 zSavedKey = p;
1818 savedKeySize = n;
1819 }else{
1820 fossil_secure_free_page(p, n);
1821 fossil_panic("bad size read, %zd out of %zu bytes at %p from pid %lu",
1822 nRead, nSize, pAddress, (unsigned long)processId);
1823 }
1824 #else
1825 fossil_secure_free_page(p, n);
1826 fossil_panic("db_read_saved_encryption_key_from_process unsupported");
1827 #endif
1828 }
1829 }
1830
1831 /*
1832 ** This function writes the saved database encryption key into the
1833 ** specified Fossil parent process. This is only necessary (or
1834 ** functional) on Windows or Linux.
1835 */
1836 static void db_write_saved_encryption_key_to_process(
1837 PID_T processId, /* Identifier for Fossil parent process. */
1838 LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
1839 SIZE_T nSize /* Size of saved key buffer in the parent process. */
1840 ){
1841 void *p = db_get_saved_encryption_key();
1842 size_t n = db_get_saved_encryption_key_size();
1843 size_t pageSize = 0;
1844
1845 fossil_get_page_size(&pageSize);
1846 assert( pageSize>0 );
1847 if( nSize>pageSize ){
1848 fossil_panic("key too large: %u versus %u", nSize, pageSize);
1849 }
1850 assert( p!=NULL );
1851 assert( n==pageSize );
1852 assert( n>=nSize );
1853 {
1854 #if defined(_WIN32)
1855 HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
1856 FALSE, processId);
1857 if( hProcess!=NULL ){
1858 SIZE_T nWrite = 0;
1859 if( WriteProcessMemory(hProcess, pAddress, p, nSize, &nWrite) ){
1860 CloseHandle(hProcess);
1861 if( nWrite!=nSize ){
1862 fossil_panic("bad size write, %u out of %u bytes at %p from pid %lu",
1863 nRead, nSize, pAddress, processId);
1864 }
1865 }else{
1866 CloseHandle(hProcess);
1867 fossil_panic("failed write, %u bytes at %p from pid %lu: %lu", nSize,
1868 pAddress, processId, GetLastError());
1869 }
1870 }else{
1871 fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1872 }
1873 #elif defined(__linux__)
1874 ssize_t nWrite;
1875 struct iovec liov = {0};
1876 struct iovec riov = {0};
1877 liov.iov_base = p;
1878 liov.iov_len = n;
1879 riov.iov_base = pAddress;
1880 riov.iov_len = nSize;
1881 nWrite = process_vm_writev(processId, &liov, 1, &riov, 1, 0);
1882 if( nWrite!=nSize ){
1883 fossil_panic("bad size write, %zd out of %zu bytes at %p from pid %lu",
1884 nWrite, nSize, pAddress, (unsigned long)processId);
1885 }
1886 #else
1887 fossil_panic("db_write_saved_encryption_key_to_process unsupported");
1888 #endif
1889 }
1890 }
1891
1892 /*
1893 ** This function zero the saved database encryption key in the specified
1894 ** Fossil parent process. This is only necessary (or functional) on
1895 ** Windows or Linux.
1896 */
1897 static void db_zero_saved_encryption_key_in_process(
1898 PID_T processId, /* Identifier for Fossil parent process. */
1899 LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
1900 SIZE_T nSize /* Size of saved key buffer in the parent process. */
1901 ){
1902 void *p = NULL;
1903 size_t n = 0;
1904 size_t pageSize = 0;
 
1905
1906 fossil_get_page_size(&pageSize);
1907 assert( pageSize>0 );
1908 if( nSize>pageSize ){
1909 fossil_panic("key too large: %u versus %u", nSize, pageSize);
@@ -1644,42 +1910,66 @@
1910 }
1911 p = fossil_secure_alloc_page(&n);
1912 assert( p!=NULL );
1913 assert( n==pageSize );
1914 assert( n>=nSize );
1915 {
1916 #if defined(_WIN32)
1917 HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
1918 FALSE, processId);
1919 if( hProcess!=NULL ){
1920 SIZE_T nWrite = 0;
1921 if( WriteProcessMemory(hProcess, pAddress, p, nSize, &nWrite) ){
1922 CloseHandle(hProcess);
1923 fossil_secure_free_page(p, n);
1924 if( nWrite!=nSize ){
1925 fossil_panic("bad size zero, %u out of %u bytes at %p from pid %lu",
1926 nRead, nSize, pAddress, processId);
1927 }
1928 }else{
1929 CloseHandle(hProcess);
1930 fossil_secure_free_page(p, n);
1931 fossil_panic("failed zero, %u bytes at %p from pid %lu: %lu", nSize,
1932 pAddress, processId, GetLastError());
1933 }
1934 }else{
1935 fossil_secure_free_page(p, n);
1936 fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
1937 }
1938 #elif defined(__linux__)
1939 ssize_t nWrite;
1940 struct iovec liov = {0};
1941 struct iovec riov = {0};
1942 liov.iov_base = p;
1943 liov.iov_len = n;
1944 riov.iov_base = pAddress;
1945 riov.iov_len = nSize;
1946 nWrite = process_vm_writev(processId, &liov, 1, &riov, 1, 0);
1947 if( nWrite!=nSize ){
1948 fossil_secure_free_page(p, n);
1949 fossil_panic("bad size zero, %zd out of %zu bytes at %p from pid %lu",
1950 nWrite, nSize, pAddress, (unsigned long)processId);
1951 }
1952 #else
1953 fossil_secure_free_page(p, n);
1954 fossil_panic("db_zero_saved_encryption_key_in_process unsupported");
1955 #endif
1956 }
1957 }
1958
1959 /*
1960 ** This function evaluates the specified TH1 script and attempts to parse
1961 ** its result as a colon-delimited triplet containing a process identifier,
1962 ** address, and size (in bytes) of the database encryption key. This is
1963 ** only necessary (or functional) on Windows or Linux.
1964 */
1965 static PID_T db_handle_saved_encryption_key_for_process_via_th1(
1966 const char *zConfig, /* The TH1 script to evaluate. */
1967 int eType /* Non-zero to write key to parent process -OR-
1968 * zero to read it from the parent process. */
1969 ){
1970 PID_T processId = 0;
1971 int rc;
1972 char *zResult;
1973 char *zPwd = file_getcwd(0, 0);
1974 Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_NEED_CONFIG | TH_INIT_NO_REPO);
1975 rc = Th_Eval(g.interp, 0, zConfig, -1);
@@ -1686,20 +1976,65 @@
1976 zResult = (char*)Th_GetResult(g.interp, 0);
1977 if( rc!=TH_OK ){
1978 fossil_fatal("script for pid key failed: %s", zResult);
1979 }
1980 if( zResult ){
 
1981 LPVOID pAddress = NULL;
1982 SIZE_T nSize = 0;
1983 parse_pid_key_value(zResult, &processId, &pAddress, &nSize);
1984 if( eType==SEE_KEY_READ ){
1985 db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
1986 }else if( eType==SEE_KEY_WRITE ){
1987 db_write_saved_encryption_key_to_process(processId, pAddress, nSize);
1988 }else if( eType==SEE_KEY_ZERO ){
1989 db_zero_saved_encryption_key_in_process(processId, pAddress, nSize);
1990 }else{
1991 fossil_panic("unsupported SEE key operation %d", eType);
1992 }
1993 }
1994 file_chdir(zPwd, 0);
1995 fossil_free(zPwd);
1996 return processId;
1997 }
1998
1999 /*
2000 ** This function sets the saved database encryption key to one that gets
2001 ** read from the specified Fossil parent process, if applicable. This is
2002 ** only necessary (or functional) on Windows or Linux.
2003 */
2004 PID_T db_maybe_handle_saved_encryption_key_for_process(int eType){
2005 PID_T processId = 0;
2006 g.zPidKey = find_option("usepidkey",0,1);
2007 if( !g.zPidKey ){
2008 g.zPidKey = fossil_getenv("FOSSIL_SEE_PID_KEY");
2009 }
2010 if( g.zPidKey ){
2011 LPVOID pAddress = NULL;
2012 SIZE_T nSize = 0;
2013 parse_pid_key_value(g.zPidKey, &processId, &pAddress, &nSize);
2014 if( eType==SEE_KEY_READ ){
2015 db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
2016 }else if( eType==SEE_KEY_WRITE ){
2017 db_write_saved_encryption_key_to_process(processId, pAddress, nSize);
2018 }else if( eType==SEE_KEY_ZERO ){
2019 db_zero_saved_encryption_key_in_process(processId, pAddress, nSize);
2020 }else{
2021 fossil_panic("unsupported SEE key operation %d", eType);
2022 }
2023 }else{
2024 const char *zSeeDbConfig = find_option("seedbcfg",0,1);
2025 if( !zSeeDbConfig ){
2026 zSeeDbConfig = fossil_getenv("FOSSIL_SEE_DB_CONFIG");
2027 }
2028 if( zSeeDbConfig ){
2029 processId = db_handle_saved_encryption_key_for_process_via_th1(
2030 zSeeDbConfig, eType
2031 );
2032 }
2033 }
2034 return processId;
2035 }
2036 #endif /* USE_SEE */
2037
2038 /*
2039 ** If the database file zDbFile has a name that suggests that it is
2040 ** encrypted, then prompt for the database encryption key and return it
2041
+43
--- src/file.c
+++ src/file.c
@@ -2277,10 +2277,53 @@
22772277
int i;
22782278
for(i=2; i<g.argc; i++){
22792279
fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
22802280
}
22812281
}
2282
+
2283
+/*
2284
+** Returns non-zero if the specified file extension belongs to a Fossil
2285
+** repository file.
2286
+*/
2287
+int file_is_repository_extension(const char *zPath){
2288
+ if( fossil_strcmp(zPath, ".fossil")==0 ) return 1;
2289
+#if USE_SEE
2290
+ if( fossil_strcmp(zPath, ".efossil")==0 ) return 1;
2291
+#endif
2292
+ return 0;
2293
+}
2294
+
2295
+/*
2296
+** Returns non-zero if the specified path appears to match a file extension
2297
+** that should belong to a Fossil repository file.
2298
+*/
2299
+int file_contains_repository_extension(const char *zPath){
2300
+ if( sqlite3_strglob("*.fossil*",zPath)==0 ) return 1;
2301
+#if USE_SEE
2302
+ if( sqlite3_strglob("*.efossil*",zPath)==0 ) return 1;
2303
+#endif
2304
+ return 0;
2305
+}
2306
+
2307
+/*
2308
+** Returns non-zero if the specified path ends with a file extension that
2309
+** should belong to a Fossil repository file.
2310
+*/
2311
+int file_ends_with_repository_extension(const char *zPath, int bQual){
2312
+ if( bQual ){
2313
+ if( sqlite3_strglob("*/*.fossil", zPath)==0 ) return 1;
2314
+#if USE_SEE
2315
+ if( sqlite3_strglob("*/*.efossil", zPath)==0 ) return 1;
2316
+#endif
2317
+ }else{
2318
+ if( sqlite3_strglob("*.fossil", zPath)==0 ) return 1;
2319
+#if USE_SEE
2320
+ if( sqlite3_strglob("*.efossil", zPath)==0 ) return 1;
2321
+#endif
2322
+ }
2323
+ return 0;
2324
+}
22822325
22832326
/*
22842327
** Remove surplus "/" characters from the beginning of a full pathname.
22852328
** Extra leading "/" characters are benign on unix. But on Windows
22862329
** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil"
22872330
--- src/file.c
+++ src/file.c
@@ -2277,10 +2277,53 @@
2277 int i;
2278 for(i=2; i<g.argc; i++){
2279 fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
2280 }
2281 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2282
2283 /*
2284 ** Remove surplus "/" characters from the beginning of a full pathname.
2285 ** Extra leading "/" characters are benign on unix. But on Windows
2286 ** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil"
2287
--- src/file.c
+++ src/file.c
@@ -2277,10 +2277,53 @@
2277 int i;
2278 for(i=2; i<g.argc; i++){
2279 fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
2280 }
2281 }
2282
2283 /*
2284 ** Returns non-zero if the specified file extension belongs to a Fossil
2285 ** repository file.
2286 */
2287 int file_is_repository_extension(const char *zPath){
2288 if( fossil_strcmp(zPath, ".fossil")==0 ) return 1;
2289 #if USE_SEE
2290 if( fossil_strcmp(zPath, ".efossil")==0 ) return 1;
2291 #endif
2292 return 0;
2293 }
2294
2295 /*
2296 ** Returns non-zero if the specified path appears to match a file extension
2297 ** that should belong to a Fossil repository file.
2298 */
2299 int file_contains_repository_extension(const char *zPath){
2300 if( sqlite3_strglob("*.fossil*",zPath)==0 ) return 1;
2301 #if USE_SEE
2302 if( sqlite3_strglob("*.efossil*",zPath)==0 ) return 1;
2303 #endif
2304 return 0;
2305 }
2306
2307 /*
2308 ** Returns non-zero if the specified path ends with a file extension that
2309 ** should belong to a Fossil repository file.
2310 */
2311 int file_ends_with_repository_extension(const char *zPath, int bQual){
2312 if( bQual ){
2313 if( sqlite3_strglob("*/*.fossil", zPath)==0 ) return 1;
2314 #if USE_SEE
2315 if( sqlite3_strglob("*/*.efossil", zPath)==0 ) return 1;
2316 #endif
2317 }else{
2318 if( sqlite3_strglob("*.fossil", zPath)==0 ) return 1;
2319 #if USE_SEE
2320 if( sqlite3_strglob("*.efossil", zPath)==0 ) return 1;
2321 #endif
2322 }
2323 return 0;
2324 }
2325
2326 /*
2327 ** Remove surplus "/" characters from the beginning of a full pathname.
2328 ** Extra leading "/" characters are benign on unix. But on Windows
2329 ** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil"
2330
+54 -36
--- src/main.c
+++ src/main.c
@@ -24,10 +24,20 @@
2424
# include <windows.h>
2525
# include <io.h>
2626
# define isatty(h) _isatty(h)
2727
# define GETPID (int)GetCurrentProcessId
2828
#endif
29
+
30
+/* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
31
+#if USE_SEE
32
+#if defined(_WIN32)
33
+typedef DWORD PID_T;
34
+#else
35
+typedef pid_t PID_T;
36
+#endif
37
+#endif
38
+
2939
#include "main.h"
3040
#include <string.h>
3141
#include <time.h>
3242
#include <fcntl.h>
3343
#include <sys/types.h>
@@ -216,13 +226,13 @@
216226
const char *zLogin; /* Login name. NULL or "" if not logged in. */
217227
const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */
218228
const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
219229
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
220230
** SSL client identity */
221
-#if defined(_WIN32) && USE_SEE
231
+#if USE_SEE
222232
const char *zPidKey; /* Saved value of the --usepidkey option. Only
223
- * applicable when using SEE on Windows. */
233
+ * applicable when using SEE on Windows or Linux. */
224234
#endif
225235
int useLocalauth; /* No login required if from 127.0.0.1 */
226236
int noPswd; /* Logged in without password (on 127.0.0.1) */
227237
int userUid; /* Integer user id */
228238
int isHuman; /* True if access by a human, not a spider or bot */
@@ -800,29 +810,12 @@
800810
if( find_option("utc",0,0) ) g.fTimeFormat = 1;
801811
if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
802812
if( zChdir && file_chdir(zChdir, 0) ){
803813
fossil_fatal("unable to change directories to %s", zChdir);
804814
}
805
-#if defined(_WIN32) && USE_SEE
806
- {
807
- g.zPidKey = find_option("usepidkey",0,1);
808
- if( g.zPidKey ){
809
- DWORD processId = 0;
810
- LPVOID pAddress = NULL;
811
- SIZE_T nSize = 0;
812
- parse_pid_key_value(g.zPidKey, &processId, &pAddress, &nSize);
813
- db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
814
- }else{
815
- const char *zSeeDbConfig = find_option("seedbcfg",0,1);
816
- if( !zSeeDbConfig ){
817
- zSeeDbConfig = fossil_getenv("FOSSIL_SEE_DB_CONFIG");
818
- }
819
- if( zSeeDbConfig ){
820
- db_read_saved_encryption_key_from_process_via_th1(zSeeDbConfig);
821
- }
822
- }
823
- }
815
+#if USE_SEE
816
+ db_maybe_handle_saved_encryption_key_for_process(SEE_KEY_READ);
824817
#endif
825818
if( find_option("help",0,0)!=0 ){
826819
/* If --help is found anywhere on the command line, translate the command
827820
* to "fossil help cmdname" where "cmdname" is the first argument that
828821
* does not begin with a "-" character. If all arguments start with "-",
@@ -1270,11 +1263,12 @@
12701263
#endif
12711264
#if defined(USE_MMAN_H)
12721265
blob_append(pOut, "USE_MMAN_H\n", -1);
12731266
#endif
12741267
#if defined(USE_SEE)
1275
- blob_append(pOut, "USE_SEE\n", -1);
1268
+ blob_appendf(pOut, "USE_SEE (%s)\n",
1269
+ db_have_saved_encryption_key() ? "SET" : "UNSET");
12761270
#endif
12771271
#if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES)
12781272
blob_append(pOut, "FOSSIL_ALLOW_OUT_OF_ORDER_DATES\n");
12791273
#endif
12801274
@@ -1716,10 +1710,11 @@
17161710
#endif
17171711
/* If the repository has not been opened already, then find the
17181712
** repository based on the first element of PATH_INFO and open it.
17191713
*/
17201714
if( !g.repositoryOpen ){
1715
+ const char *zRepoExt = ".fossil";
17211716
char *zRepo; /* Candidate repository name */
17221717
char *zToFree = 0; /* Malloced memory that needs to be freed */
17231718
const char *zCleanRepo; /* zRepo with surplus leading "/" removed */
17241719
const char *zOldScript = PD("SCRIPT_NAME", ""); /* Original SCRIPT_NAME */
17251720
char *zNewScript; /* Revised SCRIPT_NAME after processing */
@@ -1737,11 +1732,11 @@
17371732
size_t nBase = strlen(zBase);
17381733
while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
17391734
17401735
/* The candidate repository name is some prefix of the PATH_INFO
17411736
** with ".fossil" appended */
1742
- zRepo = zToFree = mprintf("%s%.*s.fossil",zBase,i,zPathInfo);
1737
+ zRepo = zToFree = mprintf("%s%.*s%s",zBase,i,zPathInfo,zRepoExt);
17431738
if( g.fHttpTrace ){
17441739
@ <!-- Looking for repository named "%h(zRepo)" -->
17451740
fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
17461741
}
17471742
@@ -1808,11 +1803,11 @@
18081803
** and check to see if there is a file or directory with the same
18091804
** name as the raw PATH_INFO text.
18101805
*/
18111806
if( szFile<0 && i>0 ){
18121807
const char *zMimetype;
1813
- assert( fossil_strcmp(&zRepo[j], ".fossil")==0 );
1808
+ assert( file_is_repository_extension(&zRepo[j]) );
18141809
zRepo[j] = 0; /* Remove the ".fossil" suffix */
18151810
18161811
/* The PATH_INFO prefix seen so far is a valid directory.
18171812
** Continue the loop with the next element of the PATH_INFO */
18181813
if( zPathInfo[i]=='/' && file_isdir(zCleanRepo, ExtFILE)==1 ){
@@ -1833,11 +1828,11 @@
18331828
** pages.
18341829
*/
18351830
if( pFileGlob!=0
18361831
&& file_isfile(zCleanRepo, ExtFILE)
18371832
&& glob_match(pFileGlob, file_cleanup_fullpath(zRepo+nBase))
1838
- && sqlite3_strglob("*.fossil*",zRepo)!=0
1833
+ && !file_contains_repository_extension(zRepo)
18391834
&& (zMimetype = mimetype_from_name(zRepo))!=0
18401835
&& strcmp(zMimetype, "application/x-fossil-artifact")!=0
18411836
){
18421837
Blob content;
18431838
blob_read_from_file(&content, file_cleanup_fullpath(zRepo), ExtFILE);
@@ -1868,10 +1863,17 @@
18681863
** string is finished. Either zRepo contains the name of the
18691864
** repository to be used, or else no repository could be found and
18701865
** some kind of error response is required.
18711866
*/
18721867
if( szFile<1024 ){
1868
+#if USE_SEE
1869
+ if( strcmp(zRepoExt,".fossil")==0 ){
1870
+ fossil_free(zToFree);
1871
+ zRepoExt = ".efossil";
1872
+ continue;
1873
+ }
1874
+#endif
18731875
set_base_url(0);
18741876
if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
18751877
&& allowRepoList
18761878
&& repo_list_page() ){
18771879
/* Will return a list of repositories */
@@ -1893,10 +1895,19 @@
18931895
if( g.zTop ) g.zTop = mprintf("%R%.*s", i, zPathInfo);
18941896
if( g.zBaseURL ) g.zBaseURL = mprintf("%s%.*s", g.zBaseURL, i, zPathInfo);
18951897
cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
18961898
zPathInfo += i;
18971899
cgi_replace_parameter("SCRIPT_NAME", zNewScript);
1900
+#if USE_SEE
1901
+ if( strcmp(zPathInfo,"/setseekey")==0
1902
+ && strcmp(zRepoExt,".efossil")==0
1903
+ && !db_have_saved_encryption_key() ){
1904
+ db_set_see_key_page();
1905
+ cgi_reply();
1906
+ fossil_exit(0);
1907
+ }
1908
+#endif
18981909
db_open_repository(file_cleanup_fullpath(zRepo));
18991910
if( g.fHttpTrace ){
19001911
@ <!-- repository: "%h(zRepo)" -->
19011912
@ <!-- translated PATH_INFO: "%h(zPathInfo)" -->
19021913
@ <!-- translated SCRIPT_NAME: "%h(zNewScript)" -->
@@ -2615,11 +2626,11 @@
26152626
}
26162627
}
26172628
}
26182629
}
26192630
2620
-#if defined(_WIN32) && USE_SEE
2631
+#if USE_SEE
26212632
/*
26222633
** This function attempts to parse a string value in the following
26232634
** format:
26242635
**
26252636
** "%lu:%p:%u"
@@ -2632,17 +2643,19 @@
26322643
**
26332644
** If the specified value cannot be parsed, for any reason, a fatal
26342645
** error will be raised and the process will be terminated.
26352646
*/
26362647
void parse_pid_key_value(
2637
- const char *zPidKey, /* The value to be parsed. */
2638
- DWORD *pProcessId, /* The extracted process identifier. */
2639
- LPVOID *ppAddress, /* The extracted pointer value. */
2640
- SIZE_T *pnSize /* The extracted size value. */
2648
+ const char *zPidKey, /* The value to be parsed. */
2649
+ PID_T *pProcessId, /* The extracted process identifier. */
2650
+ LPVOID *ppAddress, /* The extracted pointer value. */
2651
+ SIZE_T *pnSize /* The extracted size value. */
26412652
){
2653
+ unsigned long processId = 0;
26422654
unsigned int nSize = 0;
2643
- if( sscanf(zPidKey, "%lu:%p:%u", pProcessId, ppAddress, &nSize)==3 ){
2655
+ if( sscanf(zPidKey, "%lu:%p:%u", &processId, ppAddress, &nSize)==3 ){
2656
+ *pProcessId = (PID_T)processId;
26442657
*pnSize = (SIZE_T)nSize;
26452658
}else{
26462659
fossil_fatal("failed to parse pid key");
26472660
}
26482661
}
@@ -2656,25 +2669,26 @@
26562669
** Query parameters:
26572670
**
26582671
** usepidkey When present and available, also return the
26592672
** address and size, within this server process,
26602673
** of the saved database encryption key. This
2661
-** is only supported when using SEE on Windows.
2674
+** is only supported when using SEE on Windows
2675
+** or Linux.
26622676
*/
26632677
void test_pid_page(void){
26642678
login_check_credentials();
26652679
if( !g.perm.Setup ){ login_needed(0); return; }
2666
-#if defined(_WIN32) && USE_SEE
2680
+#if USE_SEE
26672681
if( P("usepidkey")!=0 ){
26682682
if( g.zPidKey ){
26692683
@ %s(g.zPidKey)
26702684
return;
26712685
}else{
26722686
const char *zSavedKey = db_get_saved_encryption_key();
26732687
size_t savedKeySize = db_get_saved_encryption_key_size();
26742688
if( zSavedKey!=0 && savedKeySize>0 ){
2675
- @ %lu(GetCurrentProcessId()):%p(zSavedKey):%u(savedKeySize)
2689
+ @ %lu(GETPID()):%p(zSavedKey):%u(savedKeySize)
26762690
return;
26772691
}
26782692
}
26792693
}
26802694
#endif
@@ -2770,11 +2784,11 @@
27702784
** --scgi Interpret input as SCGI rather than HTTP
27712785
** --skin LABEL Use override skin LABEL. Use an empty string ("")
27722786
** to force use of the current local skin config.
27732787
** --th-trace Trace TH1 execution (for debugging purposes)
27742788
** --usepidkey Use saved encryption key from parent process. This is
2775
-** only necessary when using SEE on Windows.
2789
+** only necessary when using SEE on Windows or Linux.
27762790
**
27772791
** See also: [[cgi]], [[server]], [[winsrv]]
27782792
*/
27792793
void cmd_http(void){
27802794
const char *zIpAddr = 0;
@@ -3111,11 +3125,11 @@
31113125
** --repolist If REPOSITORY is dir, URL "/" lists repos
31123126
** --scgi Accept SCGI rather than HTTP
31133127
** --skin LABEL Use override skin LABEL
31143128
** --th-trace Trace TH1 execution (for debugging purposes)
31153129
** --usepidkey Use saved encryption key from parent process. This is
3116
-** only necessary when using SEE on Windows.
3130
+** only necessary when using SEE on Windows or Linux.
31173131
**
31183132
** See also: [[cgi]], [[http]], [[winsrv]]
31193133
*/
31203134
void cmd_webserver(void){
31213135
int iPort, mxPort; /* Range of TCP ports allowed */
@@ -3140,10 +3154,14 @@
31403154
int findServerArg = 2; /* argv index for find_server_repository() */
31413155
char *zRemote = 0; /* Remote host on which to run "fossil ui" */
31423156
const char *zJsMode; /* The --jsmode parameter */
31433157
const char *zFossilCmd =0; /* Name of "fossil" binary on remote system */
31443158
3159
+
3160
+#if USE_SEE
3161
+ db_setup_for_saved_encryption_key();
3162
+#endif
31453163
31463164
#if defined(_WIN32)
31473165
const char *zStopperFile; /* Name of file used to terminate server */
31483166
zStopperFile = find_option("stopper", 0, 1);
31493167
#endif
31503168
--- src/main.c
+++ src/main.c
@@ -24,10 +24,20 @@
24 # include <windows.h>
25 # include <io.h>
26 # define isatty(h) _isatty(h)
27 # define GETPID (int)GetCurrentProcessId
28 #endif
 
 
 
 
 
 
 
 
 
 
29 #include "main.h"
30 #include <string.h>
31 #include <time.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
@@ -216,13 +226,13 @@
216 const char *zLogin; /* Login name. NULL or "" if not logged in. */
217 const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */
218 const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
219 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
220 ** SSL client identity */
221 #if defined(_WIN32) && USE_SEE
222 const char *zPidKey; /* Saved value of the --usepidkey option. Only
223 * applicable when using SEE on Windows. */
224 #endif
225 int useLocalauth; /* No login required if from 127.0.0.1 */
226 int noPswd; /* Logged in without password (on 127.0.0.1) */
227 int userUid; /* Integer user id */
228 int isHuman; /* True if access by a human, not a spider or bot */
@@ -800,29 +810,12 @@
800 if( find_option("utc",0,0) ) g.fTimeFormat = 1;
801 if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
802 if( zChdir && file_chdir(zChdir, 0) ){
803 fossil_fatal("unable to change directories to %s", zChdir);
804 }
805 #if defined(_WIN32) && USE_SEE
806 {
807 g.zPidKey = find_option("usepidkey",0,1);
808 if( g.zPidKey ){
809 DWORD processId = 0;
810 LPVOID pAddress = NULL;
811 SIZE_T nSize = 0;
812 parse_pid_key_value(g.zPidKey, &processId, &pAddress, &nSize);
813 db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
814 }else{
815 const char *zSeeDbConfig = find_option("seedbcfg",0,1);
816 if( !zSeeDbConfig ){
817 zSeeDbConfig = fossil_getenv("FOSSIL_SEE_DB_CONFIG");
818 }
819 if( zSeeDbConfig ){
820 db_read_saved_encryption_key_from_process_via_th1(zSeeDbConfig);
821 }
822 }
823 }
824 #endif
825 if( find_option("help",0,0)!=0 ){
826 /* If --help is found anywhere on the command line, translate the command
827 * to "fossil help cmdname" where "cmdname" is the first argument that
828 * does not begin with a "-" character. If all arguments start with "-",
@@ -1270,11 +1263,12 @@
1270 #endif
1271 #if defined(USE_MMAN_H)
1272 blob_append(pOut, "USE_MMAN_H\n", -1);
1273 #endif
1274 #if defined(USE_SEE)
1275 blob_append(pOut, "USE_SEE\n", -1);
 
1276 #endif
1277 #if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES)
1278 blob_append(pOut, "FOSSIL_ALLOW_OUT_OF_ORDER_DATES\n");
1279 #endif
1280
@@ -1716,10 +1710,11 @@
1716 #endif
1717 /* If the repository has not been opened already, then find the
1718 ** repository based on the first element of PATH_INFO and open it.
1719 */
1720 if( !g.repositoryOpen ){
 
1721 char *zRepo; /* Candidate repository name */
1722 char *zToFree = 0; /* Malloced memory that needs to be freed */
1723 const char *zCleanRepo; /* zRepo with surplus leading "/" removed */
1724 const char *zOldScript = PD("SCRIPT_NAME", ""); /* Original SCRIPT_NAME */
1725 char *zNewScript; /* Revised SCRIPT_NAME after processing */
@@ -1737,11 +1732,11 @@
1737 size_t nBase = strlen(zBase);
1738 while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
1739
1740 /* The candidate repository name is some prefix of the PATH_INFO
1741 ** with ".fossil" appended */
1742 zRepo = zToFree = mprintf("%s%.*s.fossil",zBase,i,zPathInfo);
1743 if( g.fHttpTrace ){
1744 @ <!-- Looking for repository named "%h(zRepo)" -->
1745 fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
1746 }
1747
@@ -1808,11 +1803,11 @@
1808 ** and check to see if there is a file or directory with the same
1809 ** name as the raw PATH_INFO text.
1810 */
1811 if( szFile<0 && i>0 ){
1812 const char *zMimetype;
1813 assert( fossil_strcmp(&zRepo[j], ".fossil")==0 );
1814 zRepo[j] = 0; /* Remove the ".fossil" suffix */
1815
1816 /* The PATH_INFO prefix seen so far is a valid directory.
1817 ** Continue the loop with the next element of the PATH_INFO */
1818 if( zPathInfo[i]=='/' && file_isdir(zCleanRepo, ExtFILE)==1 ){
@@ -1833,11 +1828,11 @@
1833 ** pages.
1834 */
1835 if( pFileGlob!=0
1836 && file_isfile(zCleanRepo, ExtFILE)
1837 && glob_match(pFileGlob, file_cleanup_fullpath(zRepo+nBase))
1838 && sqlite3_strglob("*.fossil*",zRepo)!=0
1839 && (zMimetype = mimetype_from_name(zRepo))!=0
1840 && strcmp(zMimetype, "application/x-fossil-artifact")!=0
1841 ){
1842 Blob content;
1843 blob_read_from_file(&content, file_cleanup_fullpath(zRepo), ExtFILE);
@@ -1868,10 +1863,17 @@
1868 ** string is finished. Either zRepo contains the name of the
1869 ** repository to be used, or else no repository could be found and
1870 ** some kind of error response is required.
1871 */
1872 if( szFile<1024 ){
 
 
 
 
 
 
 
1873 set_base_url(0);
1874 if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
1875 && allowRepoList
1876 && repo_list_page() ){
1877 /* Will return a list of repositories */
@@ -1893,10 +1895,19 @@
1893 if( g.zTop ) g.zTop = mprintf("%R%.*s", i, zPathInfo);
1894 if( g.zBaseURL ) g.zBaseURL = mprintf("%s%.*s", g.zBaseURL, i, zPathInfo);
1895 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
1896 zPathInfo += i;
1897 cgi_replace_parameter("SCRIPT_NAME", zNewScript);
 
 
 
 
 
 
 
 
 
1898 db_open_repository(file_cleanup_fullpath(zRepo));
1899 if( g.fHttpTrace ){
1900 @ <!-- repository: "%h(zRepo)" -->
1901 @ <!-- translated PATH_INFO: "%h(zPathInfo)" -->
1902 @ <!-- translated SCRIPT_NAME: "%h(zNewScript)" -->
@@ -2615,11 +2626,11 @@
2615 }
2616 }
2617 }
2618 }
2619
2620 #if defined(_WIN32) && USE_SEE
2621 /*
2622 ** This function attempts to parse a string value in the following
2623 ** format:
2624 **
2625 ** "%lu:%p:%u"
@@ -2632,17 +2643,19 @@
2632 **
2633 ** If the specified value cannot be parsed, for any reason, a fatal
2634 ** error will be raised and the process will be terminated.
2635 */
2636 void parse_pid_key_value(
2637 const char *zPidKey, /* The value to be parsed. */
2638 DWORD *pProcessId, /* The extracted process identifier. */
2639 LPVOID *ppAddress, /* The extracted pointer value. */
2640 SIZE_T *pnSize /* The extracted size value. */
2641 ){
 
2642 unsigned int nSize = 0;
2643 if( sscanf(zPidKey, "%lu:%p:%u", pProcessId, ppAddress, &nSize)==3 ){
 
2644 *pnSize = (SIZE_T)nSize;
2645 }else{
2646 fossil_fatal("failed to parse pid key");
2647 }
2648 }
@@ -2656,25 +2669,26 @@
2656 ** Query parameters:
2657 **
2658 ** usepidkey When present and available, also return the
2659 ** address and size, within this server process,
2660 ** of the saved database encryption key. This
2661 ** is only supported when using SEE on Windows.
 
2662 */
2663 void test_pid_page(void){
2664 login_check_credentials();
2665 if( !g.perm.Setup ){ login_needed(0); return; }
2666 #if defined(_WIN32) && USE_SEE
2667 if( P("usepidkey")!=0 ){
2668 if( g.zPidKey ){
2669 @ %s(g.zPidKey)
2670 return;
2671 }else{
2672 const char *zSavedKey = db_get_saved_encryption_key();
2673 size_t savedKeySize = db_get_saved_encryption_key_size();
2674 if( zSavedKey!=0 && savedKeySize>0 ){
2675 @ %lu(GetCurrentProcessId()):%p(zSavedKey):%u(savedKeySize)
2676 return;
2677 }
2678 }
2679 }
2680 #endif
@@ -2770,11 +2784,11 @@
2770 ** --scgi Interpret input as SCGI rather than HTTP
2771 ** --skin LABEL Use override skin LABEL. Use an empty string ("")
2772 ** to force use of the current local skin config.
2773 ** --th-trace Trace TH1 execution (for debugging purposes)
2774 ** --usepidkey Use saved encryption key from parent process. This is
2775 ** only necessary when using SEE on Windows.
2776 **
2777 ** See also: [[cgi]], [[server]], [[winsrv]]
2778 */
2779 void cmd_http(void){
2780 const char *zIpAddr = 0;
@@ -3111,11 +3125,11 @@
3111 ** --repolist If REPOSITORY is dir, URL "/" lists repos
3112 ** --scgi Accept SCGI rather than HTTP
3113 ** --skin LABEL Use override skin LABEL
3114 ** --th-trace Trace TH1 execution (for debugging purposes)
3115 ** --usepidkey Use saved encryption key from parent process. This is
3116 ** only necessary when using SEE on Windows.
3117 **
3118 ** See also: [[cgi]], [[http]], [[winsrv]]
3119 */
3120 void cmd_webserver(void){
3121 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -3140,10 +3154,14 @@
3140 int findServerArg = 2; /* argv index for find_server_repository() */
3141 char *zRemote = 0; /* Remote host on which to run "fossil ui" */
3142 const char *zJsMode; /* The --jsmode parameter */
3143 const char *zFossilCmd =0; /* Name of "fossil" binary on remote system */
3144
 
 
 
 
3145
3146 #if defined(_WIN32)
3147 const char *zStopperFile; /* Name of file used to terminate server */
3148 zStopperFile = find_option("stopper", 0, 1);
3149 #endif
3150
--- src/main.c
+++ src/main.c
@@ -24,10 +24,20 @@
24 # include <windows.h>
25 # include <io.h>
26 # define isatty(h) _isatty(h)
27 # define GETPID (int)GetCurrentProcessId
28 #endif
29
30 /* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
31 #if USE_SEE
32 #if defined(_WIN32)
33 typedef DWORD PID_T;
34 #else
35 typedef pid_t PID_T;
36 #endif
37 #endif
38
39 #include "main.h"
40 #include <string.h>
41 #include <time.h>
42 #include <fcntl.h>
43 #include <sys/types.h>
@@ -216,13 +226,13 @@
226 const char *zLogin; /* Login name. NULL or "" if not logged in. */
227 const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */
228 const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
229 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
230 ** SSL client identity */
231 #if USE_SEE
232 const char *zPidKey; /* Saved value of the --usepidkey option. Only
233 * applicable when using SEE on Windows or Linux. */
234 #endif
235 int useLocalauth; /* No login required if from 127.0.0.1 */
236 int noPswd; /* Logged in without password (on 127.0.0.1) */
237 int userUid; /* Integer user id */
238 int isHuman; /* True if access by a human, not a spider or bot */
@@ -800,29 +810,12 @@
810 if( find_option("utc",0,0) ) g.fTimeFormat = 1;
811 if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
812 if( zChdir && file_chdir(zChdir, 0) ){
813 fossil_fatal("unable to change directories to %s", zChdir);
814 }
815 #if USE_SEE
816 db_maybe_handle_saved_encryption_key_for_process(SEE_KEY_READ);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817 #endif
818 if( find_option("help",0,0)!=0 ){
819 /* If --help is found anywhere on the command line, translate the command
820 * to "fossil help cmdname" where "cmdname" is the first argument that
821 * does not begin with a "-" character. If all arguments start with "-",
@@ -1270,11 +1263,12 @@
1263 #endif
1264 #if defined(USE_MMAN_H)
1265 blob_append(pOut, "USE_MMAN_H\n", -1);
1266 #endif
1267 #if defined(USE_SEE)
1268 blob_appendf(pOut, "USE_SEE (%s)\n",
1269 db_have_saved_encryption_key() ? "SET" : "UNSET");
1270 #endif
1271 #if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES)
1272 blob_append(pOut, "FOSSIL_ALLOW_OUT_OF_ORDER_DATES\n");
1273 #endif
1274
@@ -1716,10 +1710,11 @@
1710 #endif
1711 /* If the repository has not been opened already, then find the
1712 ** repository based on the first element of PATH_INFO and open it.
1713 */
1714 if( !g.repositoryOpen ){
1715 const char *zRepoExt = ".fossil";
1716 char *zRepo; /* Candidate repository name */
1717 char *zToFree = 0; /* Malloced memory that needs to be freed */
1718 const char *zCleanRepo; /* zRepo with surplus leading "/" removed */
1719 const char *zOldScript = PD("SCRIPT_NAME", ""); /* Original SCRIPT_NAME */
1720 char *zNewScript; /* Revised SCRIPT_NAME after processing */
@@ -1737,11 +1732,11 @@
1732 size_t nBase = strlen(zBase);
1733 while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
1734
1735 /* The candidate repository name is some prefix of the PATH_INFO
1736 ** with ".fossil" appended */
1737 zRepo = zToFree = mprintf("%s%.*s%s",zBase,i,zPathInfo,zRepoExt);
1738 if( g.fHttpTrace ){
1739 @ <!-- Looking for repository named "%h(zRepo)" -->
1740 fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
1741 }
1742
@@ -1808,11 +1803,11 @@
1803 ** and check to see if there is a file or directory with the same
1804 ** name as the raw PATH_INFO text.
1805 */
1806 if( szFile<0 && i>0 ){
1807 const char *zMimetype;
1808 assert( file_is_repository_extension(&zRepo[j]) );
1809 zRepo[j] = 0; /* Remove the ".fossil" suffix */
1810
1811 /* The PATH_INFO prefix seen so far is a valid directory.
1812 ** Continue the loop with the next element of the PATH_INFO */
1813 if( zPathInfo[i]=='/' && file_isdir(zCleanRepo, ExtFILE)==1 ){
@@ -1833,11 +1828,11 @@
1828 ** pages.
1829 */
1830 if( pFileGlob!=0
1831 && file_isfile(zCleanRepo, ExtFILE)
1832 && glob_match(pFileGlob, file_cleanup_fullpath(zRepo+nBase))
1833 && !file_contains_repository_extension(zRepo)
1834 && (zMimetype = mimetype_from_name(zRepo))!=0
1835 && strcmp(zMimetype, "application/x-fossil-artifact")!=0
1836 ){
1837 Blob content;
1838 blob_read_from_file(&content, file_cleanup_fullpath(zRepo), ExtFILE);
@@ -1868,10 +1863,17 @@
1863 ** string is finished. Either zRepo contains the name of the
1864 ** repository to be used, or else no repository could be found and
1865 ** some kind of error response is required.
1866 */
1867 if( szFile<1024 ){
1868 #if USE_SEE
1869 if( strcmp(zRepoExt,".fossil")==0 ){
1870 fossil_free(zToFree);
1871 zRepoExt = ".efossil";
1872 continue;
1873 }
1874 #endif
1875 set_base_url(0);
1876 if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
1877 && allowRepoList
1878 && repo_list_page() ){
1879 /* Will return a list of repositories */
@@ -1893,10 +1895,19 @@
1895 if( g.zTop ) g.zTop = mprintf("%R%.*s", i, zPathInfo);
1896 if( g.zBaseURL ) g.zBaseURL = mprintf("%s%.*s", g.zBaseURL, i, zPathInfo);
1897 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
1898 zPathInfo += i;
1899 cgi_replace_parameter("SCRIPT_NAME", zNewScript);
1900 #if USE_SEE
1901 if( strcmp(zPathInfo,"/setseekey")==0
1902 && strcmp(zRepoExt,".efossil")==0
1903 && !db_have_saved_encryption_key() ){
1904 db_set_see_key_page();
1905 cgi_reply();
1906 fossil_exit(0);
1907 }
1908 #endif
1909 db_open_repository(file_cleanup_fullpath(zRepo));
1910 if( g.fHttpTrace ){
1911 @ <!-- repository: "%h(zRepo)" -->
1912 @ <!-- translated PATH_INFO: "%h(zPathInfo)" -->
1913 @ <!-- translated SCRIPT_NAME: "%h(zNewScript)" -->
@@ -2615,11 +2626,11 @@
2626 }
2627 }
2628 }
2629 }
2630
2631 #if USE_SEE
2632 /*
2633 ** This function attempts to parse a string value in the following
2634 ** format:
2635 **
2636 ** "%lu:%p:%u"
@@ -2632,17 +2643,19 @@
2643 **
2644 ** If the specified value cannot be parsed, for any reason, a fatal
2645 ** error will be raised and the process will be terminated.
2646 */
2647 void parse_pid_key_value(
2648 const char *zPidKey, /* The value to be parsed. */
2649 PID_T *pProcessId, /* The extracted process identifier. */
2650 LPVOID *ppAddress, /* The extracted pointer value. */
2651 SIZE_T *pnSize /* The extracted size value. */
2652 ){
2653 unsigned long processId = 0;
2654 unsigned int nSize = 0;
2655 if( sscanf(zPidKey, "%lu:%p:%u", &processId, ppAddress, &nSize)==3 ){
2656 *pProcessId = (PID_T)processId;
2657 *pnSize = (SIZE_T)nSize;
2658 }else{
2659 fossil_fatal("failed to parse pid key");
2660 }
2661 }
@@ -2656,25 +2669,26 @@
2669 ** Query parameters:
2670 **
2671 ** usepidkey When present and available, also return the
2672 ** address and size, within this server process,
2673 ** of the saved database encryption key. This
2674 ** is only supported when using SEE on Windows
2675 ** or Linux.
2676 */
2677 void test_pid_page(void){
2678 login_check_credentials();
2679 if( !g.perm.Setup ){ login_needed(0); return; }
2680 #if USE_SEE
2681 if( P("usepidkey")!=0 ){
2682 if( g.zPidKey ){
2683 @ %s(g.zPidKey)
2684 return;
2685 }else{
2686 const char *zSavedKey = db_get_saved_encryption_key();
2687 size_t savedKeySize = db_get_saved_encryption_key_size();
2688 if( zSavedKey!=0 && savedKeySize>0 ){
2689 @ %lu(GETPID()):%p(zSavedKey):%u(savedKeySize)
2690 return;
2691 }
2692 }
2693 }
2694 #endif
@@ -2770,11 +2784,11 @@
2784 ** --scgi Interpret input as SCGI rather than HTTP
2785 ** --skin LABEL Use override skin LABEL. Use an empty string ("")
2786 ** to force use of the current local skin config.
2787 ** --th-trace Trace TH1 execution (for debugging purposes)
2788 ** --usepidkey Use saved encryption key from parent process. This is
2789 ** only necessary when using SEE on Windows or Linux.
2790 **
2791 ** See also: [[cgi]], [[server]], [[winsrv]]
2792 */
2793 void cmd_http(void){
2794 const char *zIpAddr = 0;
@@ -3111,11 +3125,11 @@
3125 ** --repolist If REPOSITORY is dir, URL "/" lists repos
3126 ** --scgi Accept SCGI rather than HTTP
3127 ** --skin LABEL Use override skin LABEL
3128 ** --th-trace Trace TH1 execution (for debugging purposes)
3129 ** --usepidkey Use saved encryption key from parent process. This is
3130 ** only necessary when using SEE on Windows or Linux.
3131 **
3132 ** See also: [[cgi]], [[http]], [[winsrv]]
3133 */
3134 void cmd_webserver(void){
3135 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -3140,10 +3154,14 @@
3154 int findServerArg = 2; /* argv index for find_server_repository() */
3155 char *zRemote = 0; /* Remote host on which to run "fossil ui" */
3156 const char *zJsMode; /* The --jsmode parameter */
3157 const char *zFossilCmd =0; /* Name of "fossil" binary on remote system */
3158
3159
3160 #if USE_SEE
3161 db_setup_for_saved_encryption_key();
3162 #endif
3163
3164 #if defined(_WIN32)
3165 const char *zStopperFile; /* Name of file used to terminate server */
3166 zStopperFile = find_option("stopper", 0, 1);
3167 #endif
3168
+28 -8
--- src/repolist.c
+++ src/repolist.c
@@ -143,11 +143,15 @@
143143
blob_init(&base, g.zRepositoryName, -1);
144144
sqlite3_open(":memory:", &g.db);
145145
db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
146146
db_multi_exec("CREATE TABLE vfile(pathname);");
147147
vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
148
- db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
148
+ db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'"
149
+#if USE_SEE
150
+ " AND pathname NOT GLOB '*[^/].efossil'"
151
+#endif
152
+ );
149153
allRepo = 0;
150154
}
151155
n = db_int(0, "SELECT count(*) FROM sfile");
152156
if( n==0 ){
153157
sqlite3_close(g.db);
@@ -170,17 +174,22 @@
170174
" FROM sfile ORDER BY pathname COLLATE nocase;");
171175
rNow = db_double(0, "SELECT julianday('now')");
172176
while( db_step(&q)==SQLITE_ROW ){
173177
const char *zName = db_column_text(&q, 0);
174178
int nName = (int)strlen(zName);
179
+ int nSuffix = 7; /* ".fossil" */
175180
char *zUrl;
176181
char *zAge;
177182
char *zFull;
178183
RepoInfo x;
179184
sqlite3_int64 iAge;
180
- if( nName<7 ) continue;
181
- zUrl = sqlite3_mprintf("%.*s", nName-7, zName);
185
+#if USE_SEE
186
+ int bEncrypted = sqlite3_strglob("*.efossil", zName)==0;
187
+ if( bEncrypted ) nSuffix = 8; /* ".efossil" */
188
+#endif
189
+ if( nName<nSuffix ) continue;
190
+ zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
182191
if( zName[0]=='/'
183192
#ifdef _WIN32
184193
|| sqlite3_strglob("[a-zA-Z]:/*", zName)==0
185194
#endif
186195
){
@@ -197,11 +206,15 @@
197206
zSkinRepo = mprintf("%s", x.zRepoName);
198207
zSkinUrl = mprintf("%s", zUrl);
199208
}
200209
}
201210
fossil_free(zFull);
202
- if( !x.isValid ){
211
+ if( !x.isValid
212
+#if USE_SEE
213
+ && !bEncrypted
214
+#endif
215
+ ){
203216
continue;
204217
}
205218
if( x.isRepolistSkin==2 && !allRepo ){
206219
/* Repositories with repolist-skin==2 are omitted from directory
207220
** scan lists, but included in "fossil all ui" lists */
@@ -218,11 +231,11 @@
218231
/* This repository has no entry in the "event" table.
219232
** Its age will still be maximum, so data-sortkey will work. */
220233
zAge = mprintf("unknown");
221234
}
222235
blob_append_sql(&html, "<tr><td valign='top'>");
223
- if( sqlite3_strglob("*.fossil", zName)!=0 ){
236
+ if( !file_ends_with_repository_extension(zName,0) ){
224237
/* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands
225238
** do not work for repositories whose names do not end in ".fossil".
226239
** So do not hyperlink those cases. */
227240
blob_append_sql(&html,"%h",zName);
228241
} else if( sqlite3_strglob("*/.*", zName)==0 ){
@@ -230,21 +243,28 @@
230243
blob_append_sql(&html, "%h (hidden)", zName);
231244
} else if( allRepo && sqlite3_strglob("[a-zA-Z]:/?*", zName)!=0 ){
232245
blob_append_sql(&html,
233246
"<a href='%R/%T/home' target='_blank'>/%h</a>\n",
234247
zUrl, zName);
235
- }else if( sqlite3_strglob("*/*.fossil", zName)==0 ){
248
+ }else if( file_ends_with_repository_extension(zName,1) ){
236249
/* As described in
237250
** https://fossil-scm.org/forum/info/f50f647c97c72fc1: if
238251
** foo.fossil and foo/bar.fossil both exist and we create a
239252
** link to foo/bar/... then the URI dispatcher will instead
240253
** see that as a link to foo.fossil. In such cases, do not
241254
** emit a link to foo/bar.fossil. */
242255
char * zDirPart = file_dirname(zName);
243256
if( db_exists("SELECT 1 FROM sfile "
244
- "WHERE pathname=(%Q || '.fossil') COLLATE nocase",
245
- zDirPart) ){
257
+ "WHERE pathname=(%Q || '.fossil') COLLATE nocase"
258
+#if USE_SEE
259
+ " OR pathname=(%Q || '.efossil') COLLATE nocase"
260
+#endif
261
+ , zDirPart
262
+#if USE_SEE
263
+ , zDirPart
264
+#endif
265
+ ) ){
246266
blob_append_sql(&html,
247267
"<s>%h</s> (directory/repo name collision)\n",
248268
zName);
249269
}else{
250270
blob_append_sql(&html,
251271
--- src/repolist.c
+++ src/repolist.c
@@ -143,11 +143,15 @@
143 blob_init(&base, g.zRepositoryName, -1);
144 sqlite3_open(":memory:", &g.db);
145 db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
146 db_multi_exec("CREATE TABLE vfile(pathname);");
147 vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
148 db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
 
 
 
 
149 allRepo = 0;
150 }
151 n = db_int(0, "SELECT count(*) FROM sfile");
152 if( n==0 ){
153 sqlite3_close(g.db);
@@ -170,17 +174,22 @@
170 " FROM sfile ORDER BY pathname COLLATE nocase;");
171 rNow = db_double(0, "SELECT julianday('now')");
172 while( db_step(&q)==SQLITE_ROW ){
173 const char *zName = db_column_text(&q, 0);
174 int nName = (int)strlen(zName);
 
175 char *zUrl;
176 char *zAge;
177 char *zFull;
178 RepoInfo x;
179 sqlite3_int64 iAge;
180 if( nName<7 ) continue;
181 zUrl = sqlite3_mprintf("%.*s", nName-7, zName);
 
 
 
 
182 if( zName[0]=='/'
183 #ifdef _WIN32
184 || sqlite3_strglob("[a-zA-Z]:/*", zName)==0
185 #endif
186 ){
@@ -197,11 +206,15 @@
197 zSkinRepo = mprintf("%s", x.zRepoName);
198 zSkinUrl = mprintf("%s", zUrl);
199 }
200 }
201 fossil_free(zFull);
202 if( !x.isValid ){
 
 
 
 
203 continue;
204 }
205 if( x.isRepolistSkin==2 && !allRepo ){
206 /* Repositories with repolist-skin==2 are omitted from directory
207 ** scan lists, but included in "fossil all ui" lists */
@@ -218,11 +231,11 @@
218 /* This repository has no entry in the "event" table.
219 ** Its age will still be maximum, so data-sortkey will work. */
220 zAge = mprintf("unknown");
221 }
222 blob_append_sql(&html, "<tr><td valign='top'>");
223 if( sqlite3_strglob("*.fossil", zName)!=0 ){
224 /* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands
225 ** do not work for repositories whose names do not end in ".fossil".
226 ** So do not hyperlink those cases. */
227 blob_append_sql(&html,"%h",zName);
228 } else if( sqlite3_strglob("*/.*", zName)==0 ){
@@ -230,21 +243,28 @@
230 blob_append_sql(&html, "%h (hidden)", zName);
231 } else if( allRepo && sqlite3_strglob("[a-zA-Z]:/?*", zName)!=0 ){
232 blob_append_sql(&html,
233 "<a href='%R/%T/home' target='_blank'>/%h</a>\n",
234 zUrl, zName);
235 }else if( sqlite3_strglob("*/*.fossil", zName)==0 ){
236 /* As described in
237 ** https://fossil-scm.org/forum/info/f50f647c97c72fc1: if
238 ** foo.fossil and foo/bar.fossil both exist and we create a
239 ** link to foo/bar/... then the URI dispatcher will instead
240 ** see that as a link to foo.fossil. In such cases, do not
241 ** emit a link to foo/bar.fossil. */
242 char * zDirPart = file_dirname(zName);
243 if( db_exists("SELECT 1 FROM sfile "
244 "WHERE pathname=(%Q || '.fossil') COLLATE nocase",
245 zDirPart) ){
 
 
 
 
 
 
 
246 blob_append_sql(&html,
247 "<s>%h</s> (directory/repo name collision)\n",
248 zName);
249 }else{
250 blob_append_sql(&html,
251
--- src/repolist.c
+++ src/repolist.c
@@ -143,11 +143,15 @@
143 blob_init(&base, g.zRepositoryName, -1);
144 sqlite3_open(":memory:", &g.db);
145 db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
146 db_multi_exec("CREATE TABLE vfile(pathname);");
147 vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
148 db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'"
149 #if USE_SEE
150 " AND pathname NOT GLOB '*[^/].efossil'"
151 #endif
152 );
153 allRepo = 0;
154 }
155 n = db_int(0, "SELECT count(*) FROM sfile");
156 if( n==0 ){
157 sqlite3_close(g.db);
@@ -170,17 +174,22 @@
174 " FROM sfile ORDER BY pathname COLLATE nocase;");
175 rNow = db_double(0, "SELECT julianday('now')");
176 while( db_step(&q)==SQLITE_ROW ){
177 const char *zName = db_column_text(&q, 0);
178 int nName = (int)strlen(zName);
179 int nSuffix = 7; /* ".fossil" */
180 char *zUrl;
181 char *zAge;
182 char *zFull;
183 RepoInfo x;
184 sqlite3_int64 iAge;
185 #if USE_SEE
186 int bEncrypted = sqlite3_strglob("*.efossil", zName)==0;
187 if( bEncrypted ) nSuffix = 8; /* ".efossil" */
188 #endif
189 if( nName<nSuffix ) continue;
190 zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
191 if( zName[0]=='/'
192 #ifdef _WIN32
193 || sqlite3_strglob("[a-zA-Z]:/*", zName)==0
194 #endif
195 ){
@@ -197,11 +206,15 @@
206 zSkinRepo = mprintf("%s", x.zRepoName);
207 zSkinUrl = mprintf("%s", zUrl);
208 }
209 }
210 fossil_free(zFull);
211 if( !x.isValid
212 #if USE_SEE
213 && !bEncrypted
214 #endif
215 ){
216 continue;
217 }
218 if( x.isRepolistSkin==2 && !allRepo ){
219 /* Repositories with repolist-skin==2 are omitted from directory
220 ** scan lists, but included in "fossil all ui" lists */
@@ -218,11 +231,11 @@
231 /* This repository has no entry in the "event" table.
232 ** Its age will still be maximum, so data-sortkey will work. */
233 zAge = mprintf("unknown");
234 }
235 blob_append_sql(&html, "<tr><td valign='top'>");
236 if( !file_ends_with_repository_extension(zName,0) ){
237 /* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands
238 ** do not work for repositories whose names do not end in ".fossil".
239 ** So do not hyperlink those cases. */
240 blob_append_sql(&html,"%h",zName);
241 } else if( sqlite3_strglob("*/.*", zName)==0 ){
@@ -230,21 +243,28 @@
243 blob_append_sql(&html, "%h (hidden)", zName);
244 } else if( allRepo && sqlite3_strglob("[a-zA-Z]:/?*", zName)!=0 ){
245 blob_append_sql(&html,
246 "<a href='%R/%T/home' target='_blank'>/%h</a>\n",
247 zUrl, zName);
248 }else if( file_ends_with_repository_extension(zName,1) ){
249 /* As described in
250 ** https://fossil-scm.org/forum/info/f50f647c97c72fc1: if
251 ** foo.fossil and foo/bar.fossil both exist and we create a
252 ** link to foo/bar/... then the URI dispatcher will instead
253 ** see that as a link to foo.fossil. In such cases, do not
254 ** emit a link to foo/bar.fossil. */
255 char * zDirPart = file_dirname(zName);
256 if( db_exists("SELECT 1 FROM sfile "
257 "WHERE pathname=(%Q || '.fossil') COLLATE nocase"
258 #if USE_SEE
259 " OR pathname=(%Q || '.efossil') COLLATE nocase"
260 #endif
261 , zDirPart
262 #if USE_SEE
263 , zDirPart
264 #endif
265 ) ){
266 blob_append_sql(&html,
267 "<s>%h</s> (directory/repo name collision)\n",
268 zName);
269 }else{
270 blob_append_sql(&html,
271
+1 -1
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -287,11 +287,11 @@
287287
void fossil_key(const char **pzKey, int *pnKey){
288288
char *zSavedKey = db_get_saved_encryption_key();
289289
char *zKey;
290290
size_t savedKeySize = db_get_saved_encryption_key_size();
291291
292
- if( zSavedKey==0 || savedKeySize==0 ) return;
292
+ if( !db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ) return;
293293
zKey = (char*)malloc( savedKeySize );
294294
if( zKey ){
295295
memcpy(zKey, zSavedKey, savedKeySize);
296296
*pzKey = zKey;
297297
if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
298298
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -287,11 +287,11 @@
287 void fossil_key(const char **pzKey, int *pnKey){
288 char *zSavedKey = db_get_saved_encryption_key();
289 char *zKey;
290 size_t savedKeySize = db_get_saved_encryption_key_size();
291
292 if( zSavedKey==0 || savedKeySize==0 ) return;
293 zKey = (char*)malloc( savedKeySize );
294 if( zKey ){
295 memcpy(zKey, zSavedKey, savedKeySize);
296 *pzKey = zKey;
297 if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
298
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -287,11 +287,11 @@
287 void fossil_key(const char **pzKey, int *pnKey){
288 char *zSavedKey = db_get_saved_encryption_key();
289 char *zKey;
290 size_t savedKeySize = db_get_saved_encryption_key_size();
291
292 if( !db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ) return;
293 zKey = (char*)malloc( savedKeySize );
294 if( zKey ){
295 memcpy(zKey, zSavedKey, savedKeySize);
296 *pzKey = zKey;
297 if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
298
+1 -1
--- src/winhttp.c
+++ src/winhttp.c
@@ -625,11 +625,11 @@
625625
blob_append_escaped_arg(&options, builtin_get_js_delivery_mode_name(), 0);
626626
}
627627
#if USE_SEE
628628
zSavedKey = db_get_saved_encryption_key();
629629
savedKeySize = db_get_saved_encryption_key_size();
630
- if( zSavedKey!=0 && savedKeySize>0 ){
630
+ if( db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ){
631631
blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
632632
zSavedKey, savedKeySize);
633633
}
634634
#endif
635635
if( WSAStartup(MAKEWORD(2,0), &wd) ){
636636
--- src/winhttp.c
+++ src/winhttp.c
@@ -625,11 +625,11 @@
625 blob_append_escaped_arg(&options, builtin_get_js_delivery_mode_name(), 0);
626 }
627 #if USE_SEE
628 zSavedKey = db_get_saved_encryption_key();
629 savedKeySize = db_get_saved_encryption_key_size();
630 if( zSavedKey!=0 && savedKeySize>0 ){
631 blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
632 zSavedKey, savedKeySize);
633 }
634 #endif
635 if( WSAStartup(MAKEWORD(2,0), &wd) ){
636
--- src/winhttp.c
+++ src/winhttp.c
@@ -625,11 +625,11 @@
625 blob_append_escaped_arg(&options, builtin_get_js_delivery_mode_name(), 0);
626 }
627 #if USE_SEE
628 zSavedKey = db_get_saved_encryption_key();
629 savedKeySize = db_get_saved_encryption_key_size();
630 if( db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ){
631 blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
632 zSavedKey, savedKeySize);
633 }
634 #endif
635 if( WSAStartup(MAKEWORD(2,0), &wd) ){
636

Keyboard Shortcuts

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