Fossil SCM
Verify the repository fingerprint whenever a repository is opened from a checkout database. For now, abort with an error if the fingerprint is incorrect. To do: have Fossil automatically adjust RIDs in the checkout database if the fingerprint is incorrect.
Commit
6036bc621e10c14a0fa3ef47f79b875512b7f98a84aafc6f349717b728bf8378
Parent
e07139a05a361ed…
1 file changed
+52
-2
M
src/db.c
+52
-2
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1655,10 +1655,29 @@ | ||
| 1655 | 1655 | |
| 1656 | 1656 | /* Make a change to the CHECK constraint on the BLOB table for |
| 1657 | 1657 | ** version 2.0 and later. |
| 1658 | 1658 | */ |
| 1659 | 1659 | rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */ |
| 1660 | + | |
| 1661 | + /* If the checkout database was opened first, then check to make | |
| 1662 | + ** sure that the repository database that was just opened has not | |
| 1663 | + ** be replaced by a clone of the same project, with different RID | |
| 1664 | + ** values. | |
| 1665 | + */ | |
| 1666 | + if( g.localOpen && !db_fingerprint_ok() ){ | |
| 1667 | + fossil_print( | |
| 1668 | + "Oops. It looks like the repository database file located at\n" | |
| 1669 | + " \"%s\"\n", zDbName | |
| 1670 | + ); | |
| 1671 | + fossil_print( | |
| 1672 | + "has been swapped with a clone that may have different\n" | |
| 1673 | + "integer keys for the various artifacts. As of 2019-01-11,\n" | |
| 1674 | + "we are working on enhancing Fossil to be able to deal with\n" | |
| 1675 | + "that automatically, but we are not there yet. Sorry.\n\n" | |
| 1676 | + ); | |
| 1677 | + fossil_fatal("bad fingerprint"); | |
| 1678 | + } | |
| 1660 | 1679 | } |
| 1661 | 1680 | |
| 1662 | 1681 | /* |
| 1663 | 1682 | ** Return true if there have been any changes to the repository |
| 1664 | 1683 | ** database since it was opened. |
| @@ -3758,16 +3777,23 @@ | ||
| 3758 | 3777 | } |
| 3759 | 3778 | |
| 3760 | 3779 | /* |
| 3761 | 3780 | ** COMMAND: test-fingerprint |
| 3762 | 3781 | ** |
| 3763 | -** Usage: %fossil test-fingerprint ?RCVID? | |
| 3782 | +** Usage: %fossil test-fingerprint ?RCVID? ?--check? | |
| 3764 | 3783 | ** |
| 3765 | -** Display the repository fingerprint. | |
| 3784 | +** Display the repository fingerprint. Or if the --check option | |
| 3785 | +** is provided and this command is run from a checkout, invoke the | |
| 3786 | +** db_fingerprint_ok() method and print its result. | |
| 3766 | 3787 | */ |
| 3767 | 3788 | void test_fingerprint(void){ |
| 3768 | 3789 | int rcvid = 0; |
| 3790 | + if( find_option("check",0,0)!=0 ){ | |
| 3791 | + db_must_be_within_tree(); | |
| 3792 | + fossil_print("db_fingerprint_ok() => %d\n", db_fingerprint_ok()); | |
| 3793 | + return; | |
| 3794 | + } | |
| 3769 | 3795 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0); |
| 3770 | 3796 | if( g.argc==3 ){ |
| 3771 | 3797 | rcvid = atoi(g.argv[2]); |
| 3772 | 3798 | }else if( g.argc!=2 ){ |
| 3773 | 3799 | fossil_fatal("wrong number of arguments"); |
| @@ -3788,5 +3814,29 @@ | ||
| 3788 | 3814 | fossil_free(z); |
| 3789 | 3815 | z = db_fingerprint(0); |
| 3790 | 3816 | db_lset("fingerprint", z); |
| 3791 | 3817 | fossil_free(z); |
| 3792 | 3818 | } |
| 3819 | + | |
| 3820 | +/* | |
| 3821 | +** Verify that the fingerprint recorded in the "fingerprint" entry | |
| 3822 | +** of the VVAR table matches the fingerprint on the currently | |
| 3823 | +** connected repository. Return true if the fingerprint is ok, and | |
| 3824 | +** return false if the fingerprint does not match. | |
| 3825 | +*/ | |
| 3826 | +int db_fingerprint_ok(void){ | |
| 3827 | + char *zCkout; /* The fingerprint recorded in the checkout database */ | |
| 3828 | + char *zRepo; /* The fingerprint of the repository */ | |
| 3829 | + int rc; /* Result */ | |
| 3830 | + | |
| 3831 | + zCkout = db_text(0,"SELECT value FROM localdb.vvar WHERE name='fingerprint'"); | |
| 3832 | + if( zCkout==0 ){ | |
| 3833 | + /* This is an older checkout that does not record a fingerprint. | |
| 3834 | + ** We have to assume everything is ok */ | |
| 3835 | + return 2; | |
| 3836 | + } | |
| 3837 | + zRepo = db_fingerprint(atoi(zCkout)); | |
| 3838 | + rc = fossil_strcmp(zCkout,zRepo)==0; | |
| 3839 | + fossil_free(zCkout); | |
| 3840 | + fossil_free(zRepo); | |
| 3841 | + return rc; | |
| 3842 | +} | |
| 3793 | 3843 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1655,10 +1655,29 @@ | |
| 1655 | |
| 1656 | /* Make a change to the CHECK constraint on the BLOB table for |
| 1657 | ** version 2.0 and later. |
| 1658 | */ |
| 1659 | rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */ |
| 1660 | } |
| 1661 | |
| 1662 | /* |
| 1663 | ** Return true if there have been any changes to the repository |
| 1664 | ** database since it was opened. |
| @@ -3758,16 +3777,23 @@ | |
| 3758 | } |
| 3759 | |
| 3760 | /* |
| 3761 | ** COMMAND: test-fingerprint |
| 3762 | ** |
| 3763 | ** Usage: %fossil test-fingerprint ?RCVID? |
| 3764 | ** |
| 3765 | ** Display the repository fingerprint. |
| 3766 | */ |
| 3767 | void test_fingerprint(void){ |
| 3768 | int rcvid = 0; |
| 3769 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0); |
| 3770 | if( g.argc==3 ){ |
| 3771 | rcvid = atoi(g.argv[2]); |
| 3772 | }else if( g.argc!=2 ){ |
| 3773 | fossil_fatal("wrong number of arguments"); |
| @@ -3788,5 +3814,29 @@ | |
| 3788 | fossil_free(z); |
| 3789 | z = db_fingerprint(0); |
| 3790 | db_lset("fingerprint", z); |
| 3791 | fossil_free(z); |
| 3792 | } |
| 3793 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1655,10 +1655,29 @@ | |
| 1655 | |
| 1656 | /* Make a change to the CHECK constraint on the BLOB table for |
| 1657 | ** version 2.0 and later. |
| 1658 | */ |
| 1659 | rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */ |
| 1660 | |
| 1661 | /* If the checkout database was opened first, then check to make |
| 1662 | ** sure that the repository database that was just opened has not |
| 1663 | ** be replaced by a clone of the same project, with different RID |
| 1664 | ** values. |
| 1665 | */ |
| 1666 | if( g.localOpen && !db_fingerprint_ok() ){ |
| 1667 | fossil_print( |
| 1668 | "Oops. It looks like the repository database file located at\n" |
| 1669 | " \"%s\"\n", zDbName |
| 1670 | ); |
| 1671 | fossil_print( |
| 1672 | "has been swapped with a clone that may have different\n" |
| 1673 | "integer keys for the various artifacts. As of 2019-01-11,\n" |
| 1674 | "we are working on enhancing Fossil to be able to deal with\n" |
| 1675 | "that automatically, but we are not there yet. Sorry.\n\n" |
| 1676 | ); |
| 1677 | fossil_fatal("bad fingerprint"); |
| 1678 | } |
| 1679 | } |
| 1680 | |
| 1681 | /* |
| 1682 | ** Return true if there have been any changes to the repository |
| 1683 | ** database since it was opened. |
| @@ -3758,16 +3777,23 @@ | |
| 3777 | } |
| 3778 | |
| 3779 | /* |
| 3780 | ** COMMAND: test-fingerprint |
| 3781 | ** |
| 3782 | ** Usage: %fossil test-fingerprint ?RCVID? ?--check? |
| 3783 | ** |
| 3784 | ** Display the repository fingerprint. Or if the --check option |
| 3785 | ** is provided and this command is run from a checkout, invoke the |
| 3786 | ** db_fingerprint_ok() method and print its result. |
| 3787 | */ |
| 3788 | void test_fingerprint(void){ |
| 3789 | int rcvid = 0; |
| 3790 | if( find_option("check",0,0)!=0 ){ |
| 3791 | db_must_be_within_tree(); |
| 3792 | fossil_print("db_fingerprint_ok() => %d\n", db_fingerprint_ok()); |
| 3793 | return; |
| 3794 | } |
| 3795 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0); |
| 3796 | if( g.argc==3 ){ |
| 3797 | rcvid = atoi(g.argv[2]); |
| 3798 | }else if( g.argc!=2 ){ |
| 3799 | fossil_fatal("wrong number of arguments"); |
| @@ -3788,5 +3814,29 @@ | |
| 3814 | fossil_free(z); |
| 3815 | z = db_fingerprint(0); |
| 3816 | db_lset("fingerprint", z); |
| 3817 | fossil_free(z); |
| 3818 | } |
| 3819 | |
| 3820 | /* |
| 3821 | ** Verify that the fingerprint recorded in the "fingerprint" entry |
| 3822 | ** of the VVAR table matches the fingerprint on the currently |
| 3823 | ** connected repository. Return true if the fingerprint is ok, and |
| 3824 | ** return false if the fingerprint does not match. |
| 3825 | */ |
| 3826 | int db_fingerprint_ok(void){ |
| 3827 | char *zCkout; /* The fingerprint recorded in the checkout database */ |
| 3828 | char *zRepo; /* The fingerprint of the repository */ |
| 3829 | int rc; /* Result */ |
| 3830 | |
| 3831 | zCkout = db_text(0,"SELECT value FROM localdb.vvar WHERE name='fingerprint'"); |
| 3832 | if( zCkout==0 ){ |
| 3833 | /* This is an older checkout that does not record a fingerprint. |
| 3834 | ** We have to assume everything is ok */ |
| 3835 | return 2; |
| 3836 | } |
| 3837 | zRepo = db_fingerprint(atoi(zCkout)); |
| 3838 | rc = fossil_strcmp(zCkout,zRepo)==0; |
| 3839 | fossil_free(zCkout); |
| 3840 | fossil_free(zRepo); |
| 3841 | return rc; |
| 3842 | } |
| 3843 |