Fossil SCM

Add logic to do a configuration push. Add logic to synchronize the CONCEALED table containing hidden email addresses (assuming appropriate permissions). Additional testng is needed; this check-in is to transfer the work to another machine.

drh 2008-10-25 17:51 trunk
Commit 6b0b57a924b66439b52629bda6f6306f12fcdd96
+1 -1
--- src/clone.c
+++ src/clone.c
@@ -72,11 +72,11 @@
7272
"REPLACE INTO config(name,value)"
7373
" VALUES('server-code', lower(hex(randomblob(20))));"
7474
);
7575
url_enable_proxy(0);
7676
g.xlinkClusterOnly = 1;
77
- client_sync(0,0,1,CONFIGSET_ALL);
77
+ client_sync(0,0,1,CONFIGSET_ALL,0);
7878
g.xlinkClusterOnly = 0;
7979
verify_cancel();
8080
db_end_transaction(0);
8181
db_close();
8282
db_open_repository(g.argv[3]);
8383
--- src/clone.c
+++ src/clone.c
@@ -72,11 +72,11 @@
72 "REPLACE INTO config(name,value)"
73 " VALUES('server-code', lower(hex(randomblob(20))));"
74 );
75 url_enable_proxy(0);
76 g.xlinkClusterOnly = 1;
77 client_sync(0,0,1,CONFIGSET_ALL);
78 g.xlinkClusterOnly = 0;
79 verify_cancel();
80 db_end_transaction(0);
81 db_close();
82 db_open_repository(g.argv[3]);
83
--- src/clone.c
+++ src/clone.c
@@ -72,11 +72,11 @@
72 "REPLACE INTO config(name,value)"
73 " VALUES('server-code', lower(hex(randomblob(20))));"
74 );
75 url_enable_proxy(0);
76 g.xlinkClusterOnly = 1;
77 client_sync(0,0,1,CONFIGSET_ALL,0);
78 g.xlinkClusterOnly = 0;
79 verify_cancel();
80 db_end_transaction(0);
81 db_close();
82 db_open_repository(g.argv[3]);
83
+44 -13
--- src/configure.c
+++ src/configure.c
@@ -37,10 +37,11 @@
3737
#define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */
3838
#define CONFIGSET_TKT 0x000002 /* Ticket configuration */
3939
#define CONFIGSET_PROJ 0x000004 /* Project name */
4040
#define CONFIGSET_SHUN 0x000008 /* Shun settings */
4141
#define CONFIGSET_USER 0x000010 /* The USER table */
42
+#define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */
4243
4344
#define CONFIGSET_ALL 0xffffff /* Everything */
4445
4546
#endif /* INTERFACE */
4647
@@ -50,16 +51,17 @@
5051
static struct {
5152
const char *zName; /* Name of the configuration set */
5253
int groupMask; /* Mask for that configuration set */
5354
const char *zHelp; /* What it does */
5455
} aGroupName[] = {
55
- { "skin", CONFIGSET_SKIN, "Web interface apparance settings" },
56
- { "ticket", CONFIGSET_TKT, "Ticket setup", },
57
- { "project", CONFIGSET_PROJ, "Project name and description" },
58
- { "shun", CONFIGSET_SHUN, "List of shunned artifacts" },
59
- { "user", CONFIGSET_USER, "Users and privilege settings" },
60
- { "all", CONFIGSET_ALL, "All of the above" },
56
+ { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" },
57
+ { "project", CONFIGSET_PROJ, "Project name and description" },
58
+ { "skin", CONFIGSET_SKIN, "Web interface apparance settings" },
59
+ { "shun", CONFIGSET_SHUN, "List of shunned artifacts" },
60
+ { "ticket", CONFIGSET_TKT, "Ticket setup", },
61
+ { "user", CONFIGSET_USER, "Users and privilege settings" },
62
+ { "all", CONFIGSET_ALL, "All of the above" },
6163
};
6264
6365
6466
/*
6567
** The following is a list of settings that we are willing to
@@ -90,10 +92,11 @@
9092
{ "ticket-key-template", CONFIGSET_TKT },
9193
{ "ticket-title-expr", CONFIGSET_TKT },
9294
{ "ticket-closed-expr", CONFIGSET_TKT },
9395
{ "@reportfmt", CONFIGSET_TKT },
9496
{ "@user", CONFIGSET_USER },
97
+ { "@concealed", CONFIGSET_ADDR },
9598
{ "@shun", CONFIGSET_SHUN },
9699
};
97100
static int iConfig = 0;
98101
99102
/*
@@ -124,10 +127,13 @@
124127
if( strcmp(zName, aConfig[i].zName)==0 ){
125128
int m = aConfig[i].groupMask;
126129
if( !g.okAdmin ){
127130
m &= ~CONFIGSET_USER;
128131
}
132
+ if( !g.okRdAddr ){
133
+ m &= ~CONFIGSET_ADDR;
134
+ }
129135
return m;
130136
}
131137
}
132138
return 0;
133139
}
@@ -149,11 +155,11 @@
149155
}
150156
db_finalize(&q);
151157
}else if( strcmp(zName, "@reportfmt")==0 ){
152158
db_prepare(&q, "SELECT title, cols, sqlcode FROM reportfmt");
153159
while( db_step(&q)==SQLITE_ROW ){
154
- blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode) "
160
+ blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode)"
155161
" VALUES(%Q,%Q,%Q);\n",
156162
db_column_text(&q, 0),
157163
db_column_text(&q, 1),
158164
db_column_text(&q, 2)
159165
);
@@ -160,17 +166,27 @@
160166
}
161167
db_finalize(&q);
162168
}else if( strcmp(zName, "@user")==0 ){
163169
db_prepare(&q, "SELECT login, cap, info, quote(photo) FROM user");
164170
while( db_step(&q)==SQLITE_ROW ){
165
- blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo) "
171
+ blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo)"
166172
" VALUES(%Q,%Q,%Q,%s);\n",
167173
db_column_text(&q, 0),
168174
db_column_text(&q, 1),
169175
db_column_text(&q, 2),
170176
db_column_text(&q, 3)
171177
);
178
+ }
179
+ db_finalize(&q);
180
+ }else if( strcmp(zName, "@concealed")==0 ){
181
+ db_prepare(&q, "SELECT hash, content FROM concealed");
182
+ while( db_step(&q)==SQLITE_ROW ){
183
+ blob_appendf(pOut, "INSERT OR IGNORE INTO concealed(hash,content)"
184
+ " VALUES(%Q,%Q);\n",
185
+ db_column_text(&q, 0),
186
+ db_column_text(&q, 1)
187
+ );
172188
}
173189
db_finalize(&q);
174190
}
175191
}
176192
@@ -353,11 +369,11 @@
353369
/*
354370
** COMMAND: configuration
355371
**
356372
** Usage: %fossil configure METHOD ...
357373
**
358
-** Where METHOD is one of: export import merge pull reset. All methods
374
+** Where METHOD is one of: export import merge pull push reset. All methods
359375
** accept the -R or --repository option to specific a repository.
360376
**
361377
** %fossil configuration export AREA FILENAME
362378
**
363379
** Write to FILENAME exported configuraton information for AREA.
@@ -376,11 +392,17 @@
376392
**
377393
** %fossil configuration pull AREA ?URL?
378394
**
379395
** Pull and install the configuration from a different server
380396
** identified by URL. If no URL is specified, then the default
381
-** server is used.
397
+** server is used.
398
+**
399
+** %fossil configuration push AREA ?URL?
400
+**
401
+** Push the local configuration into the remote server identified
402
+** by URL. Admin privilege is required on the remote server for
403
+** this to work.
382404
**
383405
** %fossil configuration reset AREA
384406
**
385407
** Restore the configuration to the default. AREA as above.
386408
**
@@ -414,11 +436,11 @@
414436
configure_prepare_to_receive(zMethod[0]=='i');
415437
db_multi_exec("%s", blob_str(&in));
416438
configure_finalize_receive();
417439
db_end_transaction(0);
418440
}else
419
- if( strncmp(zMethod, "pull", n)==0 ){
441
+ if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){
420442
int mask;
421443
const char *zServer;
422444
url_proxy_options();
423445
if( g.argc!=4 && g.argc!=5 ){
424446
usage("pull AREA ?URL?");
@@ -435,11 +457,15 @@
435457
url_parse(zServer);
436458
if( g.urlIsFile ){
437459
fossil_fatal("network sync only");
438460
}
439461
user_select();
440
- client_sync(0,0,0,mask);
462
+ if( strncmp(zMethod, "push", n)==0 ){
463
+ client_sync(0,0,0,0,mask);
464
+ }else{
465
+ client_sync(0,0,0,mask,0);
466
+ }
441467
}else
442468
if( strncmp(zMethod, "reset", n)==0 ){
443469
int mask, i;
444470
char *zBackup;
445471
if( g.argc!=4 ) usage("reset AREA");
@@ -454,10 +480,14 @@
454480
if( zName[0]!='@' ){
455481
db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
456482
}else if( strcmp(zName,"@user")==0 ){
457483
db_multi_exec("DELETE FROM user");
458484
db_create_default_users();
485
+ }else if( strcmp(zName,"@concealed")==0 ){
486
+ db_multi_exec("DELETE FROM concealed");
487
+ }else if( strcmp(zName,"@shun")==0 ){
488
+ db_multi_exec("DELETE FROM shun");
459489
}else if( strcmp(zName,"@reportfmt")==0 ){
460490
db_multi_exec("DELETE FROM reportfmt");
461491
}
462492
}
463493
db_end_transaction(0);
@@ -464,8 +494,9 @@
464494
printf("Configuration reset to factory defaults.\n");
465495
printf("To recover, use: %s %s import %s\n",
466496
g.argv[0], g.argv[1], zBackup);
467497
}else
468498
{
469
- fossil_fatal("METHOD should be one of: export import merge pull reset");
499
+ fossil_fatal("METHOD should be one of:"
500
+ " export import merge pull push reset");
470501
}
471502
}
472503
--- src/configure.c
+++ src/configure.c
@@ -37,10 +37,11 @@
37 #define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */
38 #define CONFIGSET_TKT 0x000002 /* Ticket configuration */
39 #define CONFIGSET_PROJ 0x000004 /* Project name */
40 #define CONFIGSET_SHUN 0x000008 /* Shun settings */
41 #define CONFIGSET_USER 0x000010 /* The USER table */
 
42
43 #define CONFIGSET_ALL 0xffffff /* Everything */
44
45 #endif /* INTERFACE */
46
@@ -50,16 +51,17 @@
50 static struct {
51 const char *zName; /* Name of the configuration set */
52 int groupMask; /* Mask for that configuration set */
53 const char *zHelp; /* What it does */
54 } aGroupName[] = {
55 { "skin", CONFIGSET_SKIN, "Web interface apparance settings" },
56 { "ticket", CONFIGSET_TKT, "Ticket setup", },
57 { "project", CONFIGSET_PROJ, "Project name and description" },
58 { "shun", CONFIGSET_SHUN, "List of shunned artifacts" },
59 { "user", CONFIGSET_USER, "Users and privilege settings" },
60 { "all", CONFIGSET_ALL, "All of the above" },
 
61 };
62
63
64 /*
65 ** The following is a list of settings that we are willing to
@@ -90,10 +92,11 @@
90 { "ticket-key-template", CONFIGSET_TKT },
91 { "ticket-title-expr", CONFIGSET_TKT },
92 { "ticket-closed-expr", CONFIGSET_TKT },
93 { "@reportfmt", CONFIGSET_TKT },
94 { "@user", CONFIGSET_USER },
 
95 { "@shun", CONFIGSET_SHUN },
96 };
97 static int iConfig = 0;
98
99 /*
@@ -124,10 +127,13 @@
124 if( strcmp(zName, aConfig[i].zName)==0 ){
125 int m = aConfig[i].groupMask;
126 if( !g.okAdmin ){
127 m &= ~CONFIGSET_USER;
128 }
 
 
 
129 return m;
130 }
131 }
132 return 0;
133 }
@@ -149,11 +155,11 @@
149 }
150 db_finalize(&q);
151 }else if( strcmp(zName, "@reportfmt")==0 ){
152 db_prepare(&q, "SELECT title, cols, sqlcode FROM reportfmt");
153 while( db_step(&q)==SQLITE_ROW ){
154 blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode) "
155 " VALUES(%Q,%Q,%Q);\n",
156 db_column_text(&q, 0),
157 db_column_text(&q, 1),
158 db_column_text(&q, 2)
159 );
@@ -160,17 +166,27 @@
160 }
161 db_finalize(&q);
162 }else if( strcmp(zName, "@user")==0 ){
163 db_prepare(&q, "SELECT login, cap, info, quote(photo) FROM user");
164 while( db_step(&q)==SQLITE_ROW ){
165 blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo) "
166 " VALUES(%Q,%Q,%Q,%s);\n",
167 db_column_text(&q, 0),
168 db_column_text(&q, 1),
169 db_column_text(&q, 2),
170 db_column_text(&q, 3)
171 );
 
 
 
 
 
 
 
 
 
 
172 }
173 db_finalize(&q);
174 }
175 }
176
@@ -353,11 +369,11 @@
353 /*
354 ** COMMAND: configuration
355 **
356 ** Usage: %fossil configure METHOD ...
357 **
358 ** Where METHOD is one of: export import merge pull reset. All methods
359 ** accept the -R or --repository option to specific a repository.
360 **
361 ** %fossil configuration export AREA FILENAME
362 **
363 ** Write to FILENAME exported configuraton information for AREA.
@@ -376,11 +392,17 @@
376 **
377 ** %fossil configuration pull AREA ?URL?
378 **
379 ** Pull and install the configuration from a different server
380 ** identified by URL. If no URL is specified, then the default
381 ** server is used.
 
 
 
 
 
 
382 **
383 ** %fossil configuration reset AREA
384 **
385 ** Restore the configuration to the default. AREA as above.
386 **
@@ -414,11 +436,11 @@
414 configure_prepare_to_receive(zMethod[0]=='i');
415 db_multi_exec("%s", blob_str(&in));
416 configure_finalize_receive();
417 db_end_transaction(0);
418 }else
419 if( strncmp(zMethod, "pull", n)==0 ){
420 int mask;
421 const char *zServer;
422 url_proxy_options();
423 if( g.argc!=4 && g.argc!=5 ){
424 usage("pull AREA ?URL?");
@@ -435,11 +457,15 @@
435 url_parse(zServer);
436 if( g.urlIsFile ){
437 fossil_fatal("network sync only");
438 }
439 user_select();
440 client_sync(0,0,0,mask);
 
 
 
 
441 }else
442 if( strncmp(zMethod, "reset", n)==0 ){
443 int mask, i;
444 char *zBackup;
445 if( g.argc!=4 ) usage("reset AREA");
@@ -454,10 +480,14 @@
454 if( zName[0]!='@' ){
455 db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
456 }else if( strcmp(zName,"@user")==0 ){
457 db_multi_exec("DELETE FROM user");
458 db_create_default_users();
 
 
 
 
459 }else if( strcmp(zName,"@reportfmt")==0 ){
460 db_multi_exec("DELETE FROM reportfmt");
461 }
462 }
463 db_end_transaction(0);
@@ -464,8 +494,9 @@
464 printf("Configuration reset to factory defaults.\n");
465 printf("To recover, use: %s %s import %s\n",
466 g.argv[0], g.argv[1], zBackup);
467 }else
468 {
469 fossil_fatal("METHOD should be one of: export import merge pull reset");
 
470 }
471 }
472
--- src/configure.c
+++ src/configure.c
@@ -37,10 +37,11 @@
37 #define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */
38 #define CONFIGSET_TKT 0x000002 /* Ticket configuration */
39 #define CONFIGSET_PROJ 0x000004 /* Project name */
40 #define CONFIGSET_SHUN 0x000008 /* Shun settings */
41 #define CONFIGSET_USER 0x000010 /* The USER table */
42 #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */
43
44 #define CONFIGSET_ALL 0xffffff /* Everything */
45
46 #endif /* INTERFACE */
47
@@ -50,16 +51,17 @@
51 static struct {
52 const char *zName; /* Name of the configuration set */
53 int groupMask; /* Mask for that configuration set */
54 const char *zHelp; /* What it does */
55 } aGroupName[] = {
56 { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" },
57 { "project", CONFIGSET_PROJ, "Project name and description" },
58 { "skin", CONFIGSET_SKIN, "Web interface apparance settings" },
59 { "shun", CONFIGSET_SHUN, "List of shunned artifacts" },
60 { "ticket", CONFIGSET_TKT, "Ticket setup", },
61 { "user", CONFIGSET_USER, "Users and privilege settings" },
62 { "all", CONFIGSET_ALL, "All of the above" },
63 };
64
65
66 /*
67 ** The following is a list of settings that we are willing to
@@ -90,10 +92,11 @@
92 { "ticket-key-template", CONFIGSET_TKT },
93 { "ticket-title-expr", CONFIGSET_TKT },
94 { "ticket-closed-expr", CONFIGSET_TKT },
95 { "@reportfmt", CONFIGSET_TKT },
96 { "@user", CONFIGSET_USER },
97 { "@concealed", CONFIGSET_ADDR },
98 { "@shun", CONFIGSET_SHUN },
99 };
100 static int iConfig = 0;
101
102 /*
@@ -124,10 +127,13 @@
127 if( strcmp(zName, aConfig[i].zName)==0 ){
128 int m = aConfig[i].groupMask;
129 if( !g.okAdmin ){
130 m &= ~CONFIGSET_USER;
131 }
132 if( !g.okRdAddr ){
133 m &= ~CONFIGSET_ADDR;
134 }
135 return m;
136 }
137 }
138 return 0;
139 }
@@ -149,11 +155,11 @@
155 }
156 db_finalize(&q);
157 }else if( strcmp(zName, "@reportfmt")==0 ){
158 db_prepare(&q, "SELECT title, cols, sqlcode FROM reportfmt");
159 while( db_step(&q)==SQLITE_ROW ){
160 blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode)"
161 " VALUES(%Q,%Q,%Q);\n",
162 db_column_text(&q, 0),
163 db_column_text(&q, 1),
164 db_column_text(&q, 2)
165 );
@@ -160,17 +166,27 @@
166 }
167 db_finalize(&q);
168 }else if( strcmp(zName, "@user")==0 ){
169 db_prepare(&q, "SELECT login, cap, info, quote(photo) FROM user");
170 while( db_step(&q)==SQLITE_ROW ){
171 blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo)"
172 " VALUES(%Q,%Q,%Q,%s);\n",
173 db_column_text(&q, 0),
174 db_column_text(&q, 1),
175 db_column_text(&q, 2),
176 db_column_text(&q, 3)
177 );
178 }
179 db_finalize(&q);
180 }else if( strcmp(zName, "@concealed")==0 ){
181 db_prepare(&q, "SELECT hash, content FROM concealed");
182 while( db_step(&q)==SQLITE_ROW ){
183 blob_appendf(pOut, "INSERT OR IGNORE INTO concealed(hash,content)"
184 " VALUES(%Q,%Q);\n",
185 db_column_text(&q, 0),
186 db_column_text(&q, 1)
187 );
188 }
189 db_finalize(&q);
190 }
191 }
192
@@ -353,11 +369,11 @@
369 /*
370 ** COMMAND: configuration
371 **
372 ** Usage: %fossil configure METHOD ...
373 **
374 ** Where METHOD is one of: export import merge pull push reset. All methods
375 ** accept the -R or --repository option to specific a repository.
376 **
377 ** %fossil configuration export AREA FILENAME
378 **
379 ** Write to FILENAME exported configuraton information for AREA.
@@ -376,11 +392,17 @@
392 **
393 ** %fossil configuration pull AREA ?URL?
394 **
395 ** Pull and install the configuration from a different server
396 ** identified by URL. If no URL is specified, then the default
397 ** server is used.
398 **
399 ** %fossil configuration push AREA ?URL?
400 **
401 ** Push the local configuration into the remote server identified
402 ** by URL. Admin privilege is required on the remote server for
403 ** this to work.
404 **
405 ** %fossil configuration reset AREA
406 **
407 ** Restore the configuration to the default. AREA as above.
408 **
@@ -414,11 +436,11 @@
436 configure_prepare_to_receive(zMethod[0]=='i');
437 db_multi_exec("%s", blob_str(&in));
438 configure_finalize_receive();
439 db_end_transaction(0);
440 }else
441 if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){
442 int mask;
443 const char *zServer;
444 url_proxy_options();
445 if( g.argc!=4 && g.argc!=5 ){
446 usage("pull AREA ?URL?");
@@ -435,11 +457,15 @@
457 url_parse(zServer);
458 if( g.urlIsFile ){
459 fossil_fatal("network sync only");
460 }
461 user_select();
462 if( strncmp(zMethod, "push", n)==0 ){
463 client_sync(0,0,0,0,mask);
464 }else{
465 client_sync(0,0,0,mask,0);
466 }
467 }else
468 if( strncmp(zMethod, "reset", n)==0 ){
469 int mask, i;
470 char *zBackup;
471 if( g.argc!=4 ) usage("reset AREA");
@@ -454,10 +480,14 @@
480 if( zName[0]!='@' ){
481 db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
482 }else if( strcmp(zName,"@user")==0 ){
483 db_multi_exec("DELETE FROM user");
484 db_create_default_users();
485 }else if( strcmp(zName,"@concealed")==0 ){
486 db_multi_exec("DELETE FROM concealed");
487 }else if( strcmp(zName,"@shun")==0 ){
488 db_multi_exec("DELETE FROM shun");
489 }else if( strcmp(zName,"@reportfmt")==0 ){
490 db_multi_exec("DELETE FROM reportfmt");
491 }
492 }
493 db_end_transaction(0);
@@ -464,8 +494,9 @@
494 printf("Configuration reset to factory defaults.\n");
495 printf("To recover, use: %s %s import %s\n",
496 g.argv[0], g.argv[1], zBackup);
497 }else
498 {
499 fossil_fatal("METHOD should be one of:"
500 " export import merge pull push reset");
501 }
502 }
503
+22 -56
--- src/db.c
+++ src/db.c
@@ -911,30 +911,43 @@
911911
** CONCEALED table so that the hash can be undo using the db_reveal()
912912
** function at some later time.
913913
**
914914
** The value returned is stored in static space and will be overwritten
915915
** on subsequent calls.
916
+**
917
+** If zContent is already a well-formed SHA1 hash, then return a copy
918
+** of that hash, not a hash of the hash.
919
+**
920
+** The CONCEALED table is meant to obscure email addresses. Every valid
921
+** email address will contain a "@" character and "@" is not valid within
922
+** an SHA1 hash so there is no chance that a valid email address will go
923
+** unconcealed.
916924
*/
917925
char *db_conceal(const char *zContent, int n){
918926
static char zHash[42];
919927
Blob out;
920
- sha1sum_step_text(zContent, n);
921
- sha1sum_finish(&out);
922
- strcpy(zHash, blob_str(&out));
923
- blob_reset(&out);
924
- db_multi_exec(
925
- "INSERT OR IGNORE INTO concealed VALUES(%Q,%#Q)",
926
- zHash, n, zContent
927
- );
928
+ if( n==40 && validate16(zContent, n) ){
929
+ memcpy(zHash, zContent, n);
930
+ zHash[n] = 0;
931
+ }else{
932
+ sha1sum_step_text(zContent, n);
933
+ sha1sum_finish(&out);
934
+ strcpy(zHash, blob_str(&out));
935
+ blob_reset(&out);
936
+ db_multi_exec(
937
+ "INSERT OR IGNORE INTO concealed VALUES(%Q,%#Q)",
938
+ zHash, n, zContent
939
+ );
940
+ }
928941
return zHash;
929942
}
930943
931944
/*
932945
** Attempt to look up the input in the CONCEALED table. If found,
933946
** and if the okRdAddr permission is enabled then return the
934947
** original value for which the input is a hash. If okRdAddr is
935
-** false or if the lookup fails, return the original input.
948
+** false or if the lookup fails, return the original string content.
936949
**
937950
** In either case, the string returned is stored in space obtained
938951
** from malloc and should be freed by the calling function.
939952
*/
940953
char *db_reveal(const char *zKey){
@@ -948,51 +961,10 @@
948961
zOut = mprintf("%s", zKey);
949962
}
950963
return zOut;
951964
}
952965
953
-/*
954
-** The conceal() SQL function. Compute an SHA1 hash of the argument
955
-** and return that hash as a 40-character lower-case hex number.
956
-*/
957
-static void sha1_function(
958
- sqlite3_context *context,
959
- int argc,
960
- sqlite3_value **argv
961
-){
962
- const char *zIn;
963
- int nIn;
964
- char *zOut;
965
- assert(argc==1);
966
-
967
- zIn = (const char*)sqlite3_value_text(argv[0]);
968
- if( zIn ){
969
- nIn = sqlite3_value_bytes(argv[0]);
970
- zOut = db_conceal(zIn, nIn);
971
- sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
972
- }
973
-}
974
-
975
-/*
976
-** The reveal() SQL function invokes the db_reveal() function.
977
-*/
978
-static void reveal_function(
979
- sqlite3_context *context,
980
- int argc,
981
- sqlite3_value **argv
982
-){
983
- const char *zIn;
984
- char *zOut;
985
- assert(argc==1);
986
-
987
- zIn = (const char*)sqlite3_value_text(argv[0]);
988
- if( zIn ){
989
- zOut = db_reveal(zIn);
990
- sqlite3_result_text(context, zOut, -1, free);
991
- }
992
-}
993
-
994966
/*
995967
** This function registers auxiliary functions when the SQLite
996968
** database connection is first established.
997969
*/
998970
LOCAL void db_connection_init(void){
@@ -1000,16 +972,10 @@
1000972
if( once ){
1001973
sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1002974
sqlite3_create_function(
1003975
g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1004976
);
1005
- sqlite3_create_function(
1006
- g.db, "conceal", 1, SQLITE_UTF8, 0, sha1_function,0,0
1007
- );
1008
- sqlite3_create_function(
1009
- g.db, "reveal", 1, SQLITE_UTF8, 0, reveal_function,0,0
1010
- );
1011977
if( g.fSqlTrace ){
1012978
sqlite3_trace(g.db, db_sql_trace, 0);
1013979
}
1014980
once = 0;
1015981
}
1016982
--- src/db.c
+++ src/db.c
@@ -911,30 +911,43 @@
911 ** CONCEALED table so that the hash can be undo using the db_reveal()
912 ** function at some later time.
913 **
914 ** The value returned is stored in static space and will be overwritten
915 ** on subsequent calls.
 
 
 
 
 
 
 
 
916 */
917 char *db_conceal(const char *zContent, int n){
918 static char zHash[42];
919 Blob out;
920 sha1sum_step_text(zContent, n);
921 sha1sum_finish(&out);
922 strcpy(zHash, blob_str(&out));
923 blob_reset(&out);
924 db_multi_exec(
925 "INSERT OR IGNORE INTO concealed VALUES(%Q,%#Q)",
926 zHash, n, zContent
927 );
 
 
 
 
 
928 return zHash;
929 }
930
931 /*
932 ** Attempt to look up the input in the CONCEALED table. If found,
933 ** and if the okRdAddr permission is enabled then return the
934 ** original value for which the input is a hash. If okRdAddr is
935 ** false or if the lookup fails, return the original input.
936 **
937 ** In either case, the string returned is stored in space obtained
938 ** from malloc and should be freed by the calling function.
939 */
940 char *db_reveal(const char *zKey){
@@ -948,51 +961,10 @@
948 zOut = mprintf("%s", zKey);
949 }
950 return zOut;
951 }
952
953 /*
954 ** The conceal() SQL function. Compute an SHA1 hash of the argument
955 ** and return that hash as a 40-character lower-case hex number.
956 */
957 static void sha1_function(
958 sqlite3_context *context,
959 int argc,
960 sqlite3_value **argv
961 ){
962 const char *zIn;
963 int nIn;
964 char *zOut;
965 assert(argc==1);
966
967 zIn = (const char*)sqlite3_value_text(argv[0]);
968 if( zIn ){
969 nIn = sqlite3_value_bytes(argv[0]);
970 zOut = db_conceal(zIn, nIn);
971 sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
972 }
973 }
974
975 /*
976 ** The reveal() SQL function invokes the db_reveal() function.
977 */
978 static void reveal_function(
979 sqlite3_context *context,
980 int argc,
981 sqlite3_value **argv
982 ){
983 const char *zIn;
984 char *zOut;
985 assert(argc==1);
986
987 zIn = (const char*)sqlite3_value_text(argv[0]);
988 if( zIn ){
989 zOut = db_reveal(zIn);
990 sqlite3_result_text(context, zOut, -1, free);
991 }
992 }
993
994 /*
995 ** This function registers auxiliary functions when the SQLite
996 ** database connection is first established.
997 */
998 LOCAL void db_connection_init(void){
@@ -1000,16 +972,10 @@
1000 if( once ){
1001 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1002 sqlite3_create_function(
1003 g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1004 );
1005 sqlite3_create_function(
1006 g.db, "conceal", 1, SQLITE_UTF8, 0, sha1_function,0,0
1007 );
1008 sqlite3_create_function(
1009 g.db, "reveal", 1, SQLITE_UTF8, 0, reveal_function,0,0
1010 );
1011 if( g.fSqlTrace ){
1012 sqlite3_trace(g.db, db_sql_trace, 0);
1013 }
1014 once = 0;
1015 }
1016
--- src/db.c
+++ src/db.c
@@ -911,30 +911,43 @@
911 ** CONCEALED table so that the hash can be undo using the db_reveal()
912 ** function at some later time.
913 **
914 ** The value returned is stored in static space and will be overwritten
915 ** on subsequent calls.
916 **
917 ** If zContent is already a well-formed SHA1 hash, then return a copy
918 ** of that hash, not a hash of the hash.
919 **
920 ** The CONCEALED table is meant to obscure email addresses. Every valid
921 ** email address will contain a "@" character and "@" is not valid within
922 ** an SHA1 hash so there is no chance that a valid email address will go
923 ** unconcealed.
924 */
925 char *db_conceal(const char *zContent, int n){
926 static char zHash[42];
927 Blob out;
928 if( n==40 && validate16(zContent, n) ){
929 memcpy(zHash, zContent, n);
930 zHash[n] = 0;
931 }else{
932 sha1sum_step_text(zContent, n);
933 sha1sum_finish(&out);
934 strcpy(zHash, blob_str(&out));
935 blob_reset(&out);
936 db_multi_exec(
937 "INSERT OR IGNORE INTO concealed VALUES(%Q,%#Q)",
938 zHash, n, zContent
939 );
940 }
941 return zHash;
942 }
943
944 /*
945 ** Attempt to look up the input in the CONCEALED table. If found,
946 ** and if the okRdAddr permission is enabled then return the
947 ** original value for which the input is a hash. If okRdAddr is
948 ** false or if the lookup fails, return the original string content.
949 **
950 ** In either case, the string returned is stored in space obtained
951 ** from malloc and should be freed by the calling function.
952 */
953 char *db_reveal(const char *zKey){
@@ -948,51 +961,10 @@
961 zOut = mprintf("%s", zKey);
962 }
963 return zOut;
964 }
965
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
966 /*
967 ** This function registers auxiliary functions when the SQLite
968 ** database connection is first established.
969 */
970 LOCAL void db_connection_init(void){
@@ -1000,16 +972,10 @@
972 if( once ){
973 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
974 sqlite3_create_function(
975 g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
976 );
 
 
 
 
 
 
977 if( g.fSqlTrace ){
978 sqlite3_trace(g.db, db_sql_trace, 0);
979 }
980 once = 0;
981 }
982
+4 -4
--- src/sync.c
+++ src/sync.c
@@ -61,11 +61,11 @@
6161
printf("Autosync: http://%s:%d%s\n", g.urlName, g.urlPort, g.urlPath);
6262
}else{
6363
printf("Autosync: http://%s%s\n", g.urlName, g.urlPath);
6464
}
6565
url_enable_proxy("via proxy: ");
66
- client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0);
66
+ client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0);
6767
}
6868
6969
/*
7070
** This routine processes the command-line argument for push, pull,
7171
** and sync. If a command-line argument is given, that is the URL
@@ -124,11 +124,11 @@
124124
** specifies the TCP port of the server. The default port is
125125
** 80.
126126
*/
127127
void pull_cmd(void){
128128
process_sync_args();
129
- client_sync(0,1,0,0);
129
+ client_sync(0,1,0,0,0);
130130
}
131131
132132
/*
133133
** COMMAND: push
134134
**
@@ -137,11 +137,11 @@
137137
** Push changes in the local repository over into a remote repository.
138138
** See the "pull" command for additional information.
139139
*/
140140
void push_cmd(void){
141141
process_sync_args();
142
- client_sync(1,0,0,0);
142
+ client_sync(1,0,0,0,0);
143143
}
144144
145145
146146
/*
147147
** COMMAND: sync
@@ -152,7 +152,7 @@
152152
** the equivalent of running both "push" and "pull" at the same time.
153153
** See the "pull" command for additional information.
154154
*/
155155
void sync_cmd(void){
156156
process_sync_args();
157
- client_sync(1,1,0,0);
157
+ client_sync(1,1,0,0,0);
158158
}
159159
--- src/sync.c
+++ src/sync.c
@@ -61,11 +61,11 @@
61 printf("Autosync: http://%s:%d%s\n", g.urlName, g.urlPort, g.urlPath);
62 }else{
63 printf("Autosync: http://%s%s\n", g.urlName, g.urlPath);
64 }
65 url_enable_proxy("via proxy: ");
66 client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0);
67 }
68
69 /*
70 ** This routine processes the command-line argument for push, pull,
71 ** and sync. If a command-line argument is given, that is the URL
@@ -124,11 +124,11 @@
124 ** specifies the TCP port of the server. The default port is
125 ** 80.
126 */
127 void pull_cmd(void){
128 process_sync_args();
129 client_sync(0,1,0,0);
130 }
131
132 /*
133 ** COMMAND: push
134 **
@@ -137,11 +137,11 @@
137 ** Push changes in the local repository over into a remote repository.
138 ** See the "pull" command for additional information.
139 */
140 void push_cmd(void){
141 process_sync_args();
142 client_sync(1,0,0,0);
143 }
144
145
146 /*
147 ** COMMAND: sync
@@ -152,7 +152,7 @@
152 ** the equivalent of running both "push" and "pull" at the same time.
153 ** See the "pull" command for additional information.
154 */
155 void sync_cmd(void){
156 process_sync_args();
157 client_sync(1,1,0,0);
158 }
159
--- src/sync.c
+++ src/sync.c
@@ -61,11 +61,11 @@
61 printf("Autosync: http://%s:%d%s\n", g.urlName, g.urlPort, g.urlPath);
62 }else{
63 printf("Autosync: http://%s%s\n", g.urlName, g.urlPath);
64 }
65 url_enable_proxy("via proxy: ");
66 client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0);
67 }
68
69 /*
70 ** This routine processes the command-line argument for push, pull,
71 ** and sync. If a command-line argument is given, that is the URL
@@ -124,11 +124,11 @@
124 ** specifies the TCP port of the server. The default port is
125 ** 80.
126 */
127 void pull_cmd(void){
128 process_sync_args();
129 client_sync(0,1,0,0,0);
130 }
131
132 /*
133 ** COMMAND: push
134 **
@@ -137,11 +137,11 @@
137 ** Push changes in the local repository over into a remote repository.
138 ** See the "pull" command for additional information.
139 */
140 void push_cmd(void){
141 process_sync_args();
142 client_sync(1,0,0,0,0);
143 }
144
145
146 /*
147 ** COMMAND: sync
@@ -152,7 +152,7 @@
152 ** the equivalent of running both "push" and "pull" at the same time.
153 ** See the "pull" command for additional information.
154 */
155 void sync_cmd(void){
156 process_sync_args();
157 client_sync(1,1,0,0,0);
158 }
159
+103 -27
--- src/xfer.c
+++ src/xfer.c
@@ -479,10 +479,32 @@
479479
while( db_step(&q)==SQLITE_ROW ){
480480
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
481481
}
482482
db_finalize(&q);
483483
}
484
+
485
+/*
486
+** Send a single config card for configuration item zName
487
+*/
488
+static void send_config_card(Xfer *pXfer, const char *zName){
489
+ if( zName[0]!='@' ){
490
+ char *zValue = db_get(zName, 0);
491
+ if( zValue ){
492
+ blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
493
+ zName, strlen(zValue), zValue);
494
+ free(zValue);
495
+ }
496
+ }else{
497
+ Blob content;
498
+ blob_zero(&content);
499
+ configure_render_special_name(zName, &content);
500
+ blob_appendf(pXfer->pOut, "config %s %d\n%s\n", zName,
501
+ blob_size(&content), blob_str(&content));
502
+ blob_reset(&content);
503
+ }
504
+}
505
+
484506
485507
/*
486508
** If this variable is set, disable login checks. Used for debugging
487509
** only.
488510
*/
@@ -507,10 +529,12 @@
507529
int nErr = 0;
508530
Xfer xfer;
509531
int deltaFlag = 0;
510532
int isClone = 0;
511533
int nGimme = 0;
534
+ int size;
535
+ int recvConfig = 0;
512536
513537
memset(&xfer, 0, sizeof(xfer));
514538
blobarray_zero(xfer.aToken, count(xfer.aToken));
515539
cgi_set_content_type(g.zContentType);
516540
blob_zero(&xfer.err);
@@ -678,29 +702,55 @@
678702
&& xfer.nToken==2
679703
){
680704
if( g.okRead ){
681705
char *zName = blob_str(&xfer.aToken[1]);
682706
if( configure_is_exportable(zName) ){
683
- if( zName[0]!='@' ){
684
- char *zValue = db_get(zName, 0);
685
- if( zValue ){
686
- blob_appendf(xfer.pOut, "config %s %d\n%s\n", zName,
687
- strlen(zValue), zValue);
688
- free(zValue);
689
- }
690
- }else{
691
- Blob content;
692
- blob_zero(&content);
693
- configure_render_special_name(zName, &content);
694
- blob_appendf(xfer.pOut, "config %s %d\n%s\n", zName,
695
- blob_size(&content), blob_str(&content));
696
- blob_reset(&content);
697
- }
707
+ send_config_card(&xfer, zName);
698708
}
699709
}
700710
}else
701711
712
+ /* config NAME SIZE \n CONTENT
713
+ **
714
+ ** Receive a configuration value from the client. This is only
715
+ ** permitted for high-privilege users.
716
+ */
717
+ if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
718
+ && blob_is_int(&xfer.aToken[2], &size) ){
719
+ const char *zName = blob_str(&xfer.aToken[1]);
720
+ Blob content;
721
+ blob_zero(&content);
722
+ blob_extract(xfer.pIn, size, &content);
723
+ if( !g.okAdmin ){
724
+ cgi_reset_content();
725
+ @ error not\sauthorized\sto\spush\sconfiguration\data
726
+ nErr++;
727
+ break;
728
+ }
729
+ if( zName[0]!='@' ){
730
+ if( !recvConfig ){
731
+ configure_prepare_to_receive(0);
732
+ recvConfig = 1;
733
+ }
734
+ db_multi_exec(
735
+ "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
736
+ zName, blob_str(&content)
737
+ );
738
+ }else{
739
+ /* Notice that we are evaluating arbitrary SQL received from the
740
+ ** client. But this can only happen if the client has authenticated
741
+ ** as an administrator, so presumably we trust the client at this
742
+ ** point.
743
+ */
744
+ db_multi_exec("%s", blob_str(&content));
745
+ }
746
+ blob_reset(&content);
747
+ blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
748
+ }else
749
+
750
+
751
+
702752
/* cookie TEXT
703753
**
704754
** A cookie contains a arbitrary-length argument that is server-defined.
705755
** The argument must be encoded so as not to contain any whitespace.
706756
** The server can optionally send a cookie to the client. The client
@@ -742,10 +792,13 @@
742792
send_all(&xfer);
743793
}else if( isPull ){
744794
create_cluster();
745795
send_unclustered(&xfer);
746796
}
797
+ if( recvConfig ){
798
+ configure_finalize_receive();
799
+ }
747800
db_end_transaction(0);
748801
}
749802
750803
/*
751804
** COMMAND: test-xfer
@@ -793,19 +846,25 @@
793846
**
794847
** Records are pushed to the server if pushFlag is true. Records
795848
** are pulled if pullFlag is true. A full sync occurs if both are
796849
** true.
797850
*/
798
-void client_sync(int pushFlag, int pullFlag, int cloneFlag, int configMask){
851
+void client_sync(
852
+ int pushFlag, /* True to do a push (or a sync) */
853
+ int pullFlag, /* True to do a pull (or a sync) */
854
+ int cloneFlag, /* True if this is a clone */
855
+ int configRcvMask, /* Receive these configuration items */
856
+ int configSendMask /* Send these configuration items */
857
+){
799858
int go = 1; /* Loop until zero */
800859
const char *zSCode = db_get("server-code", "x");
801860
const char *zPCode = db_get("project-code", 0);
802861
int nCard = 0; /* Number of cards sent or received */
803862
int nCycle = 0; /* Number of round trips to the server */
804863
int size; /* Size of a config value */
805864
int nFileSend = 0;
806
- int origConfigMask; /* Original value of configMask */
865
+ int origConfigRcvMask; /* Original value of configRcvMask */
807866
int nFileRecv; /* Number of files received */
808867
int mxPhantomReq = 200; /* Max number of phantoms to request per comm */
809868
const char *zCookie; /* Server cookie */
810869
Blob send; /* Text we are sending to the server */
811870
Blob recv; /* Reply we got back from the server */
@@ -814,11 +873,11 @@
814873
memset(&xfer, 0, sizeof(xfer));
815874
xfer.pIn = &recv;
816875
xfer.pOut = &send;
817876
xfer.mxSend = db_get_int("max-upload", 250000);
818877
819
- assert( pushFlag || pullFlag || cloneFlag || configMask );
878
+ assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
820879
assert( !g.urlIsFile ); /* This only works for networking */
821880
822881
db_begin_transaction();
823882
db_record_repository_filename(0);
824883
db_multi_exec(
@@ -827,11 +886,11 @@
827886
blobarray_zero(xfer.aToken, count(xfer.aToken));
828887
blob_zero(&send);
829888
blob_zero(&recv);
830889
blob_zero(&xfer.err);
831890
blob_zero(&xfer.line);
832
- origConfigMask = configMask;
891
+ origConfigRcvMask = configRcvMask;
833892
834893
/*
835894
** Always begin with a clone, pull, or push message
836895
*/
837896
if( cloneFlag ){
@@ -872,22 +931,34 @@
872931
send_unsent(&xfer);
873932
nCard += send_unclustered(&xfer);
874933
}
875934
876935
/* Send configuration parameter requests */
877
- if( configMask ){
936
+ if( configRcvMask ){
878937
const char *zName;
879
- zName = configure_first_name(configMask);
938
+ zName = configure_first_name(configRcvMask);
880939
while( zName ){
881940
blob_appendf(&send, "reqconfig %s\n", zName);
882
- zName = configure_next_name(configMask);
941
+ zName = configure_next_name(configRcvMask);
883942
nCard++;
884943
}
885
- if( configMask & (CONFIGSET_USER|CONFIGSET_TKT) ){
944
+ if( configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT) ){
886945
configure_prepare_to_receive(0);
887946
}
888
- configMask = 0;
947
+ configRcvMask = 0;
948
+ }
949
+
950
+ /* Send configuration parameters being pushed */
951
+ if( configSendMask ){
952
+ const char *zName;
953
+ zName = configure_first_name(configSendMask);
954
+ while( zName ){
955
+ send_config_card(&xfer, zName);
956
+ zName = configure_next_name(configSendMask);
957
+ nCard++;
958
+ }
959
+ configSendMask = 0;
889960
}
890961
891962
/* Append randomness to the end of the message */
892963
#if 0 /* Enable this after all servers have upgraded */
893964
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
@@ -1006,17 +1077,22 @@
10061077
&& blob_is_int(&xfer.aToken[2], &size) ){
10071078
const char *zName = blob_str(&xfer.aToken[1]);
10081079
Blob content;
10091080
blob_zero(&content);
10101081
blob_extract(xfer.pIn, size, &content);
1011
- if( configure_is_exportable(zName) & origConfigMask ){
1082
+ if( configure_is_exportable(zName) & origConfigRcvMask ){
10121083
if( zName[0]!='@' ){
10131084
db_multi_exec(
10141085
"REPLACE INTO config(name,value) VALUES(%Q,%Q)",
10151086
zName, blob_str(&content)
10161087
);
10171088
}else{
1089
+ /* Notice that we are evaluating arbitrary SQL received from the
1090
+ ** server. But this can only happen if we have specifically
1091
+ ** requested configuration information from the server, so
1092
+ ** presumably the operator trusts the server.
1093
+ */
10181094
db_multi_exec("%s", blob_str(&content));
10191095
}
10201096
}
10211097
nCard++;
10221098
blob_reset(&content);
@@ -1066,14 +1142,14 @@
10661142
fossil_fatal("%b", &xfer.err);
10671143
}
10681144
blobarray_reset(xfer.aToken, xfer.nToken);
10691145
blob_reset(&xfer.line);
10701146
}
1071
- if( origConfigMask & (CONFIGSET_TKT|CONFIGSET_USER) ){
1147
+ if( origConfigRcvMask & (CONFIGSET_TKT|CONFIGSET_USER) ){
10721148
configure_finalize_receive();
10731149
}
1074
- origConfigMask = 0;
1150
+ origConfigRcvMask = 0;
10751151
printf(zValueFormat, "Received:",
10761152
blob_size(&recv), nCard,
10771153
xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
10781154
blob_reset(&recv);
10791155
nCycle++;
10801156
--- src/xfer.c
+++ src/xfer.c
@@ -479,10 +479,32 @@
479 while( db_step(&q)==SQLITE_ROW ){
480 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
481 }
482 db_finalize(&q);
483 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
485 /*
486 ** If this variable is set, disable login checks. Used for debugging
487 ** only.
488 */
@@ -507,10 +529,12 @@
507 int nErr = 0;
508 Xfer xfer;
509 int deltaFlag = 0;
510 int isClone = 0;
511 int nGimme = 0;
 
 
512
513 memset(&xfer, 0, sizeof(xfer));
514 blobarray_zero(xfer.aToken, count(xfer.aToken));
515 cgi_set_content_type(g.zContentType);
516 blob_zero(&xfer.err);
@@ -678,29 +702,55 @@
678 && xfer.nToken==2
679 ){
680 if( g.okRead ){
681 char *zName = blob_str(&xfer.aToken[1]);
682 if( configure_is_exportable(zName) ){
683 if( zName[0]!='@' ){
684 char *zValue = db_get(zName, 0);
685 if( zValue ){
686 blob_appendf(xfer.pOut, "config %s %d\n%s\n", zName,
687 strlen(zValue), zValue);
688 free(zValue);
689 }
690 }else{
691 Blob content;
692 blob_zero(&content);
693 configure_render_special_name(zName, &content);
694 blob_appendf(xfer.pOut, "config %s %d\n%s\n", zName,
695 blob_size(&content), blob_str(&content));
696 blob_reset(&content);
697 }
698 }
699 }
700 }else
701
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
702 /* cookie TEXT
703 **
704 ** A cookie contains a arbitrary-length argument that is server-defined.
705 ** The argument must be encoded so as not to contain any whitespace.
706 ** The server can optionally send a cookie to the client. The client
@@ -742,10 +792,13 @@
742 send_all(&xfer);
743 }else if( isPull ){
744 create_cluster();
745 send_unclustered(&xfer);
746 }
 
 
 
747 db_end_transaction(0);
748 }
749
750 /*
751 ** COMMAND: test-xfer
@@ -793,19 +846,25 @@
793 **
794 ** Records are pushed to the server if pushFlag is true. Records
795 ** are pulled if pullFlag is true. A full sync occurs if both are
796 ** true.
797 */
798 void client_sync(int pushFlag, int pullFlag, int cloneFlag, int configMask){
 
 
 
 
 
 
799 int go = 1; /* Loop until zero */
800 const char *zSCode = db_get("server-code", "x");
801 const char *zPCode = db_get("project-code", 0);
802 int nCard = 0; /* Number of cards sent or received */
803 int nCycle = 0; /* Number of round trips to the server */
804 int size; /* Size of a config value */
805 int nFileSend = 0;
806 int origConfigMask; /* Original value of configMask */
807 int nFileRecv; /* Number of files received */
808 int mxPhantomReq = 200; /* Max number of phantoms to request per comm */
809 const char *zCookie; /* Server cookie */
810 Blob send; /* Text we are sending to the server */
811 Blob recv; /* Reply we got back from the server */
@@ -814,11 +873,11 @@
814 memset(&xfer, 0, sizeof(xfer));
815 xfer.pIn = &recv;
816 xfer.pOut = &send;
817 xfer.mxSend = db_get_int("max-upload", 250000);
818
819 assert( pushFlag || pullFlag || cloneFlag || configMask );
820 assert( !g.urlIsFile ); /* This only works for networking */
821
822 db_begin_transaction();
823 db_record_repository_filename(0);
824 db_multi_exec(
@@ -827,11 +886,11 @@
827 blobarray_zero(xfer.aToken, count(xfer.aToken));
828 blob_zero(&send);
829 blob_zero(&recv);
830 blob_zero(&xfer.err);
831 blob_zero(&xfer.line);
832 origConfigMask = configMask;
833
834 /*
835 ** Always begin with a clone, pull, or push message
836 */
837 if( cloneFlag ){
@@ -872,22 +931,34 @@
872 send_unsent(&xfer);
873 nCard += send_unclustered(&xfer);
874 }
875
876 /* Send configuration parameter requests */
877 if( configMask ){
878 const char *zName;
879 zName = configure_first_name(configMask);
880 while( zName ){
881 blob_appendf(&send, "reqconfig %s\n", zName);
882 zName = configure_next_name(configMask);
883 nCard++;
884 }
885 if( configMask & (CONFIGSET_USER|CONFIGSET_TKT) ){
886 configure_prepare_to_receive(0);
887 }
888 configMask = 0;
 
 
 
 
 
 
 
 
 
 
 
 
889 }
890
891 /* Append randomness to the end of the message */
892 #if 0 /* Enable this after all servers have upgraded */
893 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
@@ -1006,17 +1077,22 @@
1006 && blob_is_int(&xfer.aToken[2], &size) ){
1007 const char *zName = blob_str(&xfer.aToken[1]);
1008 Blob content;
1009 blob_zero(&content);
1010 blob_extract(xfer.pIn, size, &content);
1011 if( configure_is_exportable(zName) & origConfigMask ){
1012 if( zName[0]!='@' ){
1013 db_multi_exec(
1014 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1015 zName, blob_str(&content)
1016 );
1017 }else{
 
 
 
 
 
1018 db_multi_exec("%s", blob_str(&content));
1019 }
1020 }
1021 nCard++;
1022 blob_reset(&content);
@@ -1066,14 +1142,14 @@
1066 fossil_fatal("%b", &xfer.err);
1067 }
1068 blobarray_reset(xfer.aToken, xfer.nToken);
1069 blob_reset(&xfer.line);
1070 }
1071 if( origConfigMask & (CONFIGSET_TKT|CONFIGSET_USER) ){
1072 configure_finalize_receive();
1073 }
1074 origConfigMask = 0;
1075 printf(zValueFormat, "Received:",
1076 blob_size(&recv), nCard,
1077 xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
1078 blob_reset(&recv);
1079 nCycle++;
1080
--- src/xfer.c
+++ src/xfer.c
@@ -479,10 +479,32 @@
479 while( db_step(&q)==SQLITE_ROW ){
480 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
481 }
482 db_finalize(&q);
483 }
484
485 /*
486 ** Send a single config card for configuration item zName
487 */
488 static void send_config_card(Xfer *pXfer, const char *zName){
489 if( zName[0]!='@' ){
490 char *zValue = db_get(zName, 0);
491 if( zValue ){
492 blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
493 zName, strlen(zValue), zValue);
494 free(zValue);
495 }
496 }else{
497 Blob content;
498 blob_zero(&content);
499 configure_render_special_name(zName, &content);
500 blob_appendf(pXfer->pOut, "config %s %d\n%s\n", zName,
501 blob_size(&content), blob_str(&content));
502 blob_reset(&content);
503 }
504 }
505
506
507 /*
508 ** If this variable is set, disable login checks. Used for debugging
509 ** only.
510 */
@@ -507,10 +529,12 @@
529 int nErr = 0;
530 Xfer xfer;
531 int deltaFlag = 0;
532 int isClone = 0;
533 int nGimme = 0;
534 int size;
535 int recvConfig = 0;
536
537 memset(&xfer, 0, sizeof(xfer));
538 blobarray_zero(xfer.aToken, count(xfer.aToken));
539 cgi_set_content_type(g.zContentType);
540 blob_zero(&xfer.err);
@@ -678,29 +702,55 @@
702 && xfer.nToken==2
703 ){
704 if( g.okRead ){
705 char *zName = blob_str(&xfer.aToken[1]);
706 if( configure_is_exportable(zName) ){
707 send_config_card(&xfer, zName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
708 }
709 }
710 }else
711
712 /* config NAME SIZE \n CONTENT
713 **
714 ** Receive a configuration value from the client. This is only
715 ** permitted for high-privilege users.
716 */
717 if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
718 && blob_is_int(&xfer.aToken[2], &size) ){
719 const char *zName = blob_str(&xfer.aToken[1]);
720 Blob content;
721 blob_zero(&content);
722 blob_extract(xfer.pIn, size, &content);
723 if( !g.okAdmin ){
724 cgi_reset_content();
725 @ error not\sauthorized\sto\spush\sconfiguration\data
726 nErr++;
727 break;
728 }
729 if( zName[0]!='@' ){
730 if( !recvConfig ){
731 configure_prepare_to_receive(0);
732 recvConfig = 1;
733 }
734 db_multi_exec(
735 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
736 zName, blob_str(&content)
737 );
738 }else{
739 /* Notice that we are evaluating arbitrary SQL received from the
740 ** client. But this can only happen if the client has authenticated
741 ** as an administrator, so presumably we trust the client at this
742 ** point.
743 */
744 db_multi_exec("%s", blob_str(&content));
745 }
746 blob_reset(&content);
747 blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
748 }else
749
750
751
752 /* cookie TEXT
753 **
754 ** A cookie contains a arbitrary-length argument that is server-defined.
755 ** The argument must be encoded so as not to contain any whitespace.
756 ** The server can optionally send a cookie to the client. The client
@@ -742,10 +792,13 @@
792 send_all(&xfer);
793 }else if( isPull ){
794 create_cluster();
795 send_unclustered(&xfer);
796 }
797 if( recvConfig ){
798 configure_finalize_receive();
799 }
800 db_end_transaction(0);
801 }
802
803 /*
804 ** COMMAND: test-xfer
@@ -793,19 +846,25 @@
846 **
847 ** Records are pushed to the server if pushFlag is true. Records
848 ** are pulled if pullFlag is true. A full sync occurs if both are
849 ** true.
850 */
851 void client_sync(
852 int pushFlag, /* True to do a push (or a sync) */
853 int pullFlag, /* True to do a pull (or a sync) */
854 int cloneFlag, /* True if this is a clone */
855 int configRcvMask, /* Receive these configuration items */
856 int configSendMask /* Send these configuration items */
857 ){
858 int go = 1; /* Loop until zero */
859 const char *zSCode = db_get("server-code", "x");
860 const char *zPCode = db_get("project-code", 0);
861 int nCard = 0; /* Number of cards sent or received */
862 int nCycle = 0; /* Number of round trips to the server */
863 int size; /* Size of a config value */
864 int nFileSend = 0;
865 int origConfigRcvMask; /* Original value of configRcvMask */
866 int nFileRecv; /* Number of files received */
867 int mxPhantomReq = 200; /* Max number of phantoms to request per comm */
868 const char *zCookie; /* Server cookie */
869 Blob send; /* Text we are sending to the server */
870 Blob recv; /* Reply we got back from the server */
@@ -814,11 +873,11 @@
873 memset(&xfer, 0, sizeof(xfer));
874 xfer.pIn = &recv;
875 xfer.pOut = &send;
876 xfer.mxSend = db_get_int("max-upload", 250000);
877
878 assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
879 assert( !g.urlIsFile ); /* This only works for networking */
880
881 db_begin_transaction();
882 db_record_repository_filename(0);
883 db_multi_exec(
@@ -827,11 +886,11 @@
886 blobarray_zero(xfer.aToken, count(xfer.aToken));
887 blob_zero(&send);
888 blob_zero(&recv);
889 blob_zero(&xfer.err);
890 blob_zero(&xfer.line);
891 origConfigRcvMask = configRcvMask;
892
893 /*
894 ** Always begin with a clone, pull, or push message
895 */
896 if( cloneFlag ){
@@ -872,22 +931,34 @@
931 send_unsent(&xfer);
932 nCard += send_unclustered(&xfer);
933 }
934
935 /* Send configuration parameter requests */
936 if( configRcvMask ){
937 const char *zName;
938 zName = configure_first_name(configRcvMask);
939 while( zName ){
940 blob_appendf(&send, "reqconfig %s\n", zName);
941 zName = configure_next_name(configRcvMask);
942 nCard++;
943 }
944 if( configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT) ){
945 configure_prepare_to_receive(0);
946 }
947 configRcvMask = 0;
948 }
949
950 /* Send configuration parameters being pushed */
951 if( configSendMask ){
952 const char *zName;
953 zName = configure_first_name(configSendMask);
954 while( zName ){
955 send_config_card(&xfer, zName);
956 zName = configure_next_name(configSendMask);
957 nCard++;
958 }
959 configSendMask = 0;
960 }
961
962 /* Append randomness to the end of the message */
963 #if 0 /* Enable this after all servers have upgraded */
964 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
@@ -1006,17 +1077,22 @@
1077 && blob_is_int(&xfer.aToken[2], &size) ){
1078 const char *zName = blob_str(&xfer.aToken[1]);
1079 Blob content;
1080 blob_zero(&content);
1081 blob_extract(xfer.pIn, size, &content);
1082 if( configure_is_exportable(zName) & origConfigRcvMask ){
1083 if( zName[0]!='@' ){
1084 db_multi_exec(
1085 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1086 zName, blob_str(&content)
1087 );
1088 }else{
1089 /* Notice that we are evaluating arbitrary SQL received from the
1090 ** server. But this can only happen if we have specifically
1091 ** requested configuration information from the server, so
1092 ** presumably the operator trusts the server.
1093 */
1094 db_multi_exec("%s", blob_str(&content));
1095 }
1096 }
1097 nCard++;
1098 blob_reset(&content);
@@ -1066,14 +1142,14 @@
1142 fossil_fatal("%b", &xfer.err);
1143 }
1144 blobarray_reset(xfer.aToken, xfer.nToken);
1145 blob_reset(&xfer.line);
1146 }
1147 if( origConfigRcvMask & (CONFIGSET_TKT|CONFIGSET_USER) ){
1148 configure_finalize_receive();
1149 }
1150 origConfigRcvMask = 0;
1151 printf(zValueFormat, "Received:",
1152 blob_size(&recv), nCard,
1153 xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
1154 blob_reset(&recv);
1155 nCycle++;
1156

Keyboard Shortcuts

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