Fossil SCM
Merge experimental remote-url password handling changes into the trunk.
Commit
a3c97c9063bfe5b451233f38e21bdf7341c0bd49
Parent
1abc8a940ee2ef7…
7 files changed
+5
+10
-18
+1
+1
-1
+27
-23
+26
-5
+29
-11
+5
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -445,24 +445,29 @@ | ||
| 445 | 445 | db_end_transaction(0); |
| 446 | 446 | }else |
| 447 | 447 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 448 | 448 | int mask; |
| 449 | 449 | const char *zServer; |
| 450 | + const char *zPw; | |
| 450 | 451 | url_proxy_options(); |
| 451 | 452 | if( g.argc!=4 && g.argc!=5 ){ |
| 452 | 453 | usage("pull AREA ?URL?"); |
| 453 | 454 | } |
| 454 | 455 | mask = find_area(g.argv[3]); |
| 455 | 456 | if( g.argc==5 ){ |
| 456 | 457 | zServer = g.argv[4]; |
| 458 | + zPw = 0; | |
| 459 | + g.dontKeepUrl = 1; | |
| 457 | 460 | }else{ |
| 458 | 461 | zServer = db_get("last-sync-url", 0); |
| 459 | 462 | if( zServer==0 ){ |
| 460 | 463 | fossil_fatal("no server specified"); |
| 461 | 464 | } |
| 465 | + zPw = db_get("last-sync-pw", 0); | |
| 462 | 466 | } |
| 463 | 467 | url_parse(zServer); |
| 468 | + if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); | |
| 464 | 469 | user_select(); |
| 465 | 470 | if( strncmp(zMethod, "push", n)==0 ){ |
| 466 | 471 | client_sync(0,0,0,0,mask); |
| 467 | 472 | }else{ |
| 468 | 473 | client_sync(0,0,0,mask,0); |
| 469 | 474 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -445,24 +445,29 @@ | |
| 445 | db_end_transaction(0); |
| 446 | }else |
| 447 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 448 | int mask; |
| 449 | const char *zServer; |
| 450 | url_proxy_options(); |
| 451 | if( g.argc!=4 && g.argc!=5 ){ |
| 452 | usage("pull AREA ?URL?"); |
| 453 | } |
| 454 | mask = find_area(g.argv[3]); |
| 455 | if( g.argc==5 ){ |
| 456 | zServer = g.argv[4]; |
| 457 | }else{ |
| 458 | zServer = db_get("last-sync-url", 0); |
| 459 | if( zServer==0 ){ |
| 460 | fossil_fatal("no server specified"); |
| 461 | } |
| 462 | } |
| 463 | url_parse(zServer); |
| 464 | user_select(); |
| 465 | if( strncmp(zMethod, "push", n)==0 ){ |
| 466 | client_sync(0,0,0,0,mask); |
| 467 | }else{ |
| 468 | client_sync(0,0,0,mask,0); |
| 469 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -445,24 +445,29 @@ | |
| 445 | db_end_transaction(0); |
| 446 | }else |
| 447 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 448 | int mask; |
| 449 | const char *zServer; |
| 450 | const char *zPw; |
| 451 | url_proxy_options(); |
| 452 | if( g.argc!=4 && g.argc!=5 ){ |
| 453 | usage("pull AREA ?URL?"); |
| 454 | } |
| 455 | mask = find_area(g.argv[3]); |
| 456 | if( g.argc==5 ){ |
| 457 | zServer = g.argv[4]; |
| 458 | zPw = 0; |
| 459 | g.dontKeepUrl = 1; |
| 460 | }else{ |
| 461 | zServer = db_get("last-sync-url", 0); |
| 462 | if( zServer==0 ){ |
| 463 | fossil_fatal("no server specified"); |
| 464 | } |
| 465 | zPw = db_get("last-sync-pw", 0); |
| 466 | } |
| 467 | url_parse(zServer); |
| 468 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 469 | user_select(); |
| 470 | if( strncmp(zMethod, "push", n)==0 ){ |
| 471 | client_sync(0,0,0,0,mask); |
| 472 | }else{ |
| 473 | client_sync(0,0,0,mask,0); |
| 474 |
+10
-18
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -44,33 +44,25 @@ | ||
| 44 | 44 | const char *zLogin; /* The user login name */ |
| 45 | 45 | const char *zPw; /* The user password */ |
| 46 | 46 | Blob pw; /* The nonce with user password appended */ |
| 47 | 47 | Blob sig; /* The signature field */ |
| 48 | 48 | |
| 49 | + blob_zero(pLogin); | |
| 50 | + if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){ | |
| 51 | + return; /* If no login card for users "nobody" and "anonymous" */ | |
| 52 | + } | |
| 49 | 53 | blob_zero(&nonce); |
| 50 | 54 | blob_zero(&pw); |
| 51 | 55 | sha1sum_blob(pPayload, &nonce); |
| 52 | 56 | blob_copy(&pw, &nonce); |
| 53 | - blob_zero(pLogin); | |
| 54 | - if( g.urlUser==0 ){ | |
| 55 | - user_select(); | |
| 56 | - zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", g.userUid); | |
| 57 | - zLogin = g.zLogin; | |
| 58 | - }else{ | |
| 59 | - if( g.urlPasswd==0 ){ | |
| 60 | - if( strcmp(g.urlUser,"anonymous")!=0 ){ | |
| 61 | - char *zPrompt = mprintf("password for %s: ", g.urlUser); | |
| 62 | - Blob x; | |
| 63 | - prompt_for_password(zPrompt, &x, 0); | |
| 64 | - free(zPrompt); | |
| 65 | - g.urlPasswd = blob_str(&x); | |
| 66 | - }else{ | |
| 67 | - g.urlPasswd = ""; | |
| 68 | - } | |
| 69 | - } | |
| 57 | + zLogin = g.urlUser; | |
| 58 | + if( g.urlPasswd ){ | |
| 59 | + zPw = g.urlPasswd; | |
| 60 | + }else{ | |
| 61 | + url_prompt_for_password(); | |
| 70 | 62 | zPw = g.urlPasswd; |
| 71 | - zLogin = g.urlUser; | |
| 63 | + if( !g.dontKeepUrl ) db_set("last-sync-pw", zPw, 0); | |
| 72 | 64 | } |
| 73 | 65 | |
| 74 | 66 | /* The login card wants the SHA1 hash of the password, so convert the |
| 75 | 67 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 76 | 68 | ** |
| 77 | 69 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -44,33 +44,25 @@ | |
| 44 | const char *zLogin; /* The user login name */ |
| 45 | const char *zPw; /* The user password */ |
| 46 | Blob pw; /* The nonce with user password appended */ |
| 47 | Blob sig; /* The signature field */ |
| 48 | |
| 49 | blob_zero(&nonce); |
| 50 | blob_zero(&pw); |
| 51 | sha1sum_blob(pPayload, &nonce); |
| 52 | blob_copy(&pw, &nonce); |
| 53 | blob_zero(pLogin); |
| 54 | if( g.urlUser==0 ){ |
| 55 | user_select(); |
| 56 | zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", g.userUid); |
| 57 | zLogin = g.zLogin; |
| 58 | }else{ |
| 59 | if( g.urlPasswd==0 ){ |
| 60 | if( strcmp(g.urlUser,"anonymous")!=0 ){ |
| 61 | char *zPrompt = mprintf("password for %s: ", g.urlUser); |
| 62 | Blob x; |
| 63 | prompt_for_password(zPrompt, &x, 0); |
| 64 | free(zPrompt); |
| 65 | g.urlPasswd = blob_str(&x); |
| 66 | }else{ |
| 67 | g.urlPasswd = ""; |
| 68 | } |
| 69 | } |
| 70 | zPw = g.urlPasswd; |
| 71 | zLogin = g.urlUser; |
| 72 | } |
| 73 | |
| 74 | /* The login card wants the SHA1 hash of the password, so convert the |
| 75 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 76 | ** |
| 77 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -44,33 +44,25 @@ | |
| 44 | const char *zLogin; /* The user login name */ |
| 45 | const char *zPw; /* The user password */ |
| 46 | Blob pw; /* The nonce with user password appended */ |
| 47 | Blob sig; /* The signature field */ |
| 48 | |
| 49 | blob_zero(pLogin); |
| 50 | if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){ |
| 51 | return; /* If no login card for users "nobody" and "anonymous" */ |
| 52 | } |
| 53 | blob_zero(&nonce); |
| 54 | blob_zero(&pw); |
| 55 | sha1sum_blob(pPayload, &nonce); |
| 56 | blob_copy(&pw, &nonce); |
| 57 | zLogin = g.urlUser; |
| 58 | if( g.urlPasswd ){ |
| 59 | zPw = g.urlPasswd; |
| 60 | }else{ |
| 61 | url_prompt_for_password(); |
| 62 | zPw = g.urlPasswd; |
| 63 | if( !g.dontKeepUrl ) db_set("last-sync-pw", zPw, 0); |
| 64 | } |
| 65 | |
| 66 | /* The login card wants the SHA1 hash of the password, so convert the |
| 67 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 68 | ** |
| 69 |
+1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -101,10 +101,11 @@ | ||
| 101 | 101 | char *urlPath; /* Pathname for http: */ |
| 102 | 102 | char *urlUser; /* User id for http: */ |
| 103 | 103 | char *urlPasswd; /* Password for http: */ |
| 104 | 104 | char *urlCanonical; /* Canonical representation of the URL */ |
| 105 | 105 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 106 | + int dontKeepUrl; /* Do not persist the URL */ | |
| 106 | 107 | |
| 107 | 108 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 108 | 109 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 109 | 110 | int userUid; /* Integer user id */ |
| 110 | 111 | |
| 111 | 112 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -101,10 +101,11 @@ | |
| 101 | char *urlPath; /* Pathname for http: */ |
| 102 | char *urlUser; /* User id for http: */ |
| 103 | char *urlPasswd; /* Password for http: */ |
| 104 | char *urlCanonical; /* Canonical representation of the URL */ |
| 105 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 106 | |
| 107 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 108 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 109 | int userUid; /* Integer user id */ |
| 110 | |
| 111 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -101,10 +101,11 @@ | |
| 101 | char *urlPath; /* Pathname for http: */ |
| 102 | char *urlUser; /* User id for http: */ |
| 103 | char *urlPasswd; /* Password for http: */ |
| 104 | char *urlCanonical; /* Canonical representation of the URL */ |
| 105 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 106 | int dontKeepUrl; /* Do not persist the URL */ |
| 107 | |
| 108 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 109 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 110 | int userUid; /* Integer user id */ |
| 111 | |
| 112 |
+1
-1
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -384,11 +384,11 @@ | ||
| 384 | 384 | } |
| 385 | 385 | } |
| 386 | 386 | db_begin_transaction(); |
| 387 | 387 | db_multi_exec( |
| 388 | 388 | "UPDATE user SET pw='';" |
| 389 | - "DELETE FROM config WHERE name='last-sync-url';" | |
| 389 | + "DELETE FROM config WHERE name GLOB 'last-sync-*';" | |
| 390 | 390 | ); |
| 391 | 391 | if( bVerily ){ |
| 392 | 392 | bNeedRebuild = db_exists("SELECT 1 FROM private"); |
| 393 | 393 | db_multi_exec( |
| 394 | 394 | "DELETE FROM concealed;" |
| 395 | 395 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -384,11 +384,11 @@ | |
| 384 | } |
| 385 | } |
| 386 | db_begin_transaction(); |
| 387 | db_multi_exec( |
| 388 | "UPDATE user SET pw='';" |
| 389 | "DELETE FROM config WHERE name='last-sync-url';" |
| 390 | ); |
| 391 | if( bVerily ){ |
| 392 | bNeedRebuild = db_exists("SELECT 1 FROM private"); |
| 393 | db_multi_exec( |
| 394 | "DELETE FROM concealed;" |
| 395 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -384,11 +384,11 @@ | |
| 384 | } |
| 385 | } |
| 386 | db_begin_transaction(); |
| 387 | db_multi_exec( |
| 388 | "UPDATE user SET pw='';" |
| 389 | "DELETE FROM config WHERE name GLOB 'last-sync-*';" |
| 390 | ); |
| 391 | if( bVerily ){ |
| 392 | bNeedRebuild = db_exists("SELECT 1 FROM private"); |
| 393 | db_multi_exec( |
| 394 | "DELETE FROM concealed;" |
| 395 |
+27
-23
| --- src/sync.c | ||
| +++ src/sync.c | ||
| @@ -42,10 +42,11 @@ | ||
| 42 | 42 | ** if the argument is false. |
| 43 | 43 | */ |
| 44 | 44 | void autosync(int flags){ |
| 45 | 45 | const char *zUrl; |
| 46 | 46 | const char *zAutosync; |
| 47 | + const char *zPw; | |
| 47 | 48 | if( g.fNoSync ){ |
| 48 | 49 | return; |
| 49 | 50 | } |
| 50 | 51 | zAutosync = db_get("autosync", 0); |
| 51 | 52 | if( zAutosync ){ |
| @@ -60,17 +61,16 @@ | ||
| 60 | 61 | } |
| 61 | 62 | zUrl = db_get("last-sync-url", 0); |
| 62 | 63 | if( zUrl==0 ){ |
| 63 | 64 | return; /* No default server */ |
| 64 | 65 | } |
| 66 | + zPw = db_get("last-sync-pw", 0); | |
| 65 | 67 | url_parse(zUrl); |
| 66 | - if( g.urlPort!=g.urlDfltPort ){ | |
| 67 | - printf("Autosync: %s://%s:%d%s\n", | |
| 68 | - g.urlProtocol, g.urlName, g.urlPort, g.urlPath); | |
| 69 | - }else{ | |
| 70 | - printf("Autosync: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); | |
| 68 | + if( g.urlUser!=0 && g.urlPasswd==0 ){ | |
| 69 | + g.urlPasswd = mprintf("%s", zPw); | |
| 71 | 70 | } |
| 71 | + printf("Autosync: %s\n", g.urlCanonical); | |
| 72 | 72 | url_enable_proxy("via proxy: "); |
| 73 | 73 | client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0); |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | /* |
| @@ -79,35 +79,36 @@ | ||
| 79 | 79 | ** of a server to sync against. If no argument is given, use the |
| 80 | 80 | ** most recently synced URL. Remember the current URL for next time. |
| 81 | 81 | */ |
| 82 | 82 | void process_sync_args(void){ |
| 83 | 83 | const char *zUrl = 0; |
| 84 | + const char *zPw = 0; | |
| 84 | 85 | int urlOptional = find_option("autourl",0,0)!=0; |
| 85 | - int dontKeepUrl = find_option("once",0,0)!=0; | |
| 86 | + g.dontKeepUrl = find_option("once",0,0)!=0; | |
| 86 | 87 | url_proxy_options(); |
| 87 | 88 | db_find_and_open_repository(1); |
| 88 | 89 | if( g.argc==2 ){ |
| 89 | 90 | zUrl = db_get("last-sync-url", 0); |
| 91 | + zPw = db_get("last-sync-pw", 0); | |
| 90 | 92 | }else if( g.argc==3 ){ |
| 91 | 93 | zUrl = g.argv[2]; |
| 92 | 94 | } |
| 93 | 95 | if( zUrl==0 ){ |
| 94 | 96 | if( urlOptional ) exit(0); |
| 95 | 97 | usage("URL"); |
| 96 | 98 | } |
| 97 | 99 | url_parse(zUrl); |
| 98 | - if( !dontKeepUrl ){ | |
| 99 | - db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : zUrl, 0); | |
| 100 | + if( !g.dontKeepUrl ){ | |
| 101 | + db_set("last-sync-url", g.urlCanonical, 0); | |
| 102 | + if( g.urlPasswd ) db_set("last-sync-pw", g.urlPasswd, 0); | |
| 103 | + } | |
| 104 | + if( g.urlUser!=0 && g.urlPasswd==0 ){ | |
| 105 | + g.urlPasswd = mprintf("%s", zPw); | |
| 100 | 106 | } |
| 101 | 107 | user_select(); |
| 102 | 108 | if( g.argc==2 ){ |
| 103 | - if( g.urlPort!=g.urlDfltPort ){ | |
| 104 | - printf("Server: %s://%s:%d%s\n", | |
| 105 | - g.urlProtocol, g.urlName, g.urlPort, g.urlPath); | |
| 106 | - }else{ | |
| 107 | - printf("Server: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); | |
| 108 | - } | |
| 109 | + printf("Server: %s\n", g.urlCanonical); | |
| 109 | 110 | } |
| 110 | 111 | url_enable_proxy("via proxy: "); |
| 111 | 112 | } |
| 112 | 113 | |
| 113 | 114 | /* |
| @@ -189,46 +190,49 @@ | ||
| 189 | 190 | } |
| 190 | 191 | |
| 191 | 192 | /* |
| 192 | 193 | ** COMMAND: remote-url |
| 193 | 194 | ** |
| 194 | -** Usage: %fossil remote-url ?URL|off? --show-pw | |
| 195 | +** Usage: %fossil remote-url ?URL|off? | |
| 195 | 196 | ** |
| 196 | 197 | ** Query and/or change the default server URL used by the "pull", "push", |
| 197 | 198 | ** and "sync" commands. |
| 198 | 199 | ** |
| 199 | -** The userid and password are of the URL are not printed unless | |
| 200 | -** the --show-pw option is used on the command-line. | |
| 201 | -** | |
| 202 | 200 | ** The remote-url is set automatically by a "clone" command or by any |
| 203 | 201 | ** "sync", "push", or "pull" command that specifies an explicit URL. |
| 204 | 202 | ** The default remote-url is used by auto-syncing and by "sync", "push", |
| 205 | 203 | ** "pull" that omit the server URL. |
| 206 | 204 | ** |
| 207 | 205 | ** See also: clone, push, pull, sync |
| 208 | 206 | */ |
| 209 | 207 | void remote_url_cmd(void){ |
| 210 | 208 | char *zUrl; |
| 211 | - int showPw = find_option("show-pw",0,0)!=0; | |
| 212 | 209 | db_find_and_open_repository(1); |
| 213 | 210 | if( g.argc!=2 && g.argc!=3 ){ |
| 214 | 211 | usage("remote-url ?URL|off?"); |
| 215 | 212 | } |
| 216 | 213 | if( g.argc==3 ){ |
| 217 | 214 | if( strcmp(g.argv[2],"off")==0 ){ |
| 218 | 215 | db_unset("last-sync-url", 0); |
| 216 | + db_unset("last-sync-pw", 0); | |
| 219 | 217 | }else{ |
| 220 | 218 | url_parse(g.argv[2]); |
| 221 | - db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : g.argv[2], 0); | |
| 219 | + if( g.urlUser && g.urlPasswd==0 ){ | |
| 220 | + url_prompt_for_password(); | |
| 221 | + } | |
| 222 | + db_set("last-sync-url", g.urlCanonical, 0); | |
| 223 | + if( g.urlPasswd ){ | |
| 224 | + db_set("last-sync-pw", g.urlPasswd, 0); | |
| 225 | + }else{ | |
| 226 | + db_unset("last-sync-pw", 0); | |
| 227 | + } | |
| 222 | 228 | } |
| 223 | 229 | } |
| 224 | 230 | zUrl = db_get("last-sync-url", 0); |
| 225 | 231 | if( zUrl==0 ){ |
| 226 | 232 | printf("off\n"); |
| 227 | 233 | return; |
| 228 | - }else if( showPw ){ | |
| 229 | - g.urlCanonical = zUrl; | |
| 230 | 234 | }else{ |
| 231 | 235 | url_parse(zUrl); |
| 236 | + printf("%s\n", g.urlCanonical); | |
| 232 | 237 | } |
| 233 | - printf("%s\n", g.urlCanonical); | |
| 234 | 238 | } |
| 235 | 239 |
| --- src/sync.c | |
| +++ src/sync.c | |
| @@ -42,10 +42,11 @@ | |
| 42 | ** if the argument is false. |
| 43 | */ |
| 44 | void autosync(int flags){ |
| 45 | const char *zUrl; |
| 46 | const char *zAutosync; |
| 47 | if( g.fNoSync ){ |
| 48 | return; |
| 49 | } |
| 50 | zAutosync = db_get("autosync", 0); |
| 51 | if( zAutosync ){ |
| @@ -60,17 +61,16 @@ | |
| 60 | } |
| 61 | zUrl = db_get("last-sync-url", 0); |
| 62 | if( zUrl==0 ){ |
| 63 | return; /* No default server */ |
| 64 | } |
| 65 | url_parse(zUrl); |
| 66 | if( g.urlPort!=g.urlDfltPort ){ |
| 67 | printf("Autosync: %s://%s:%d%s\n", |
| 68 | g.urlProtocol, g.urlName, g.urlPort, g.urlPath); |
| 69 | }else{ |
| 70 | printf("Autosync: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); |
| 71 | } |
| 72 | url_enable_proxy("via proxy: "); |
| 73 | client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0); |
| 74 | } |
| 75 | |
| 76 | /* |
| @@ -79,35 +79,36 @@ | |
| 79 | ** of a server to sync against. If no argument is given, use the |
| 80 | ** most recently synced URL. Remember the current URL for next time. |
| 81 | */ |
| 82 | void process_sync_args(void){ |
| 83 | const char *zUrl = 0; |
| 84 | int urlOptional = find_option("autourl",0,0)!=0; |
| 85 | int dontKeepUrl = find_option("once",0,0)!=0; |
| 86 | url_proxy_options(); |
| 87 | db_find_and_open_repository(1); |
| 88 | if( g.argc==2 ){ |
| 89 | zUrl = db_get("last-sync-url", 0); |
| 90 | }else if( g.argc==3 ){ |
| 91 | zUrl = g.argv[2]; |
| 92 | } |
| 93 | if( zUrl==0 ){ |
| 94 | if( urlOptional ) exit(0); |
| 95 | usage("URL"); |
| 96 | } |
| 97 | url_parse(zUrl); |
| 98 | if( !dontKeepUrl ){ |
| 99 | db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : zUrl, 0); |
| 100 | } |
| 101 | user_select(); |
| 102 | if( g.argc==2 ){ |
| 103 | if( g.urlPort!=g.urlDfltPort ){ |
| 104 | printf("Server: %s://%s:%d%s\n", |
| 105 | g.urlProtocol, g.urlName, g.urlPort, g.urlPath); |
| 106 | }else{ |
| 107 | printf("Server: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); |
| 108 | } |
| 109 | } |
| 110 | url_enable_proxy("via proxy: "); |
| 111 | } |
| 112 | |
| 113 | /* |
| @@ -189,46 +190,49 @@ | |
| 189 | } |
| 190 | |
| 191 | /* |
| 192 | ** COMMAND: remote-url |
| 193 | ** |
| 194 | ** Usage: %fossil remote-url ?URL|off? --show-pw |
| 195 | ** |
| 196 | ** Query and/or change the default server URL used by the "pull", "push", |
| 197 | ** and "sync" commands. |
| 198 | ** |
| 199 | ** The userid and password are of the URL are not printed unless |
| 200 | ** the --show-pw option is used on the command-line. |
| 201 | ** |
| 202 | ** The remote-url is set automatically by a "clone" command or by any |
| 203 | ** "sync", "push", or "pull" command that specifies an explicit URL. |
| 204 | ** The default remote-url is used by auto-syncing and by "sync", "push", |
| 205 | ** "pull" that omit the server URL. |
| 206 | ** |
| 207 | ** See also: clone, push, pull, sync |
| 208 | */ |
| 209 | void remote_url_cmd(void){ |
| 210 | char *zUrl; |
| 211 | int showPw = find_option("show-pw",0,0)!=0; |
| 212 | db_find_and_open_repository(1); |
| 213 | if( g.argc!=2 && g.argc!=3 ){ |
| 214 | usage("remote-url ?URL|off?"); |
| 215 | } |
| 216 | if( g.argc==3 ){ |
| 217 | if( strcmp(g.argv[2],"off")==0 ){ |
| 218 | db_unset("last-sync-url", 0); |
| 219 | }else{ |
| 220 | url_parse(g.argv[2]); |
| 221 | db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : g.argv[2], 0); |
| 222 | } |
| 223 | } |
| 224 | zUrl = db_get("last-sync-url", 0); |
| 225 | if( zUrl==0 ){ |
| 226 | printf("off\n"); |
| 227 | return; |
| 228 | }else if( showPw ){ |
| 229 | g.urlCanonical = zUrl; |
| 230 | }else{ |
| 231 | url_parse(zUrl); |
| 232 | } |
| 233 | printf("%s\n", g.urlCanonical); |
| 234 | } |
| 235 |
| --- src/sync.c | |
| +++ src/sync.c | |
| @@ -42,10 +42,11 @@ | |
| 42 | ** if the argument is false. |
| 43 | */ |
| 44 | void autosync(int flags){ |
| 45 | const char *zUrl; |
| 46 | const char *zAutosync; |
| 47 | const char *zPw; |
| 48 | if( g.fNoSync ){ |
| 49 | return; |
| 50 | } |
| 51 | zAutosync = db_get("autosync", 0); |
| 52 | if( zAutosync ){ |
| @@ -60,17 +61,16 @@ | |
| 61 | } |
| 62 | zUrl = db_get("last-sync-url", 0); |
| 63 | if( zUrl==0 ){ |
| 64 | return; /* No default server */ |
| 65 | } |
| 66 | zPw = db_get("last-sync-pw", 0); |
| 67 | url_parse(zUrl); |
| 68 | if( g.urlUser!=0 && g.urlPasswd==0 ){ |
| 69 | g.urlPasswd = mprintf("%s", zPw); |
| 70 | } |
| 71 | printf("Autosync: %s\n", g.urlCanonical); |
| 72 | url_enable_proxy("via proxy: "); |
| 73 | client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0); |
| 74 | } |
| 75 | |
| 76 | /* |
| @@ -79,35 +79,36 @@ | |
| 79 | ** of a server to sync against. If no argument is given, use the |
| 80 | ** most recently synced URL. Remember the current URL for next time. |
| 81 | */ |
| 82 | void process_sync_args(void){ |
| 83 | const char *zUrl = 0; |
| 84 | const char *zPw = 0; |
| 85 | int urlOptional = find_option("autourl",0,0)!=0; |
| 86 | g.dontKeepUrl = find_option("once",0,0)!=0; |
| 87 | url_proxy_options(); |
| 88 | db_find_and_open_repository(1); |
| 89 | if( g.argc==2 ){ |
| 90 | zUrl = db_get("last-sync-url", 0); |
| 91 | zPw = db_get("last-sync-pw", 0); |
| 92 | }else if( g.argc==3 ){ |
| 93 | zUrl = g.argv[2]; |
| 94 | } |
| 95 | if( zUrl==0 ){ |
| 96 | if( urlOptional ) exit(0); |
| 97 | usage("URL"); |
| 98 | } |
| 99 | url_parse(zUrl); |
| 100 | if( !g.dontKeepUrl ){ |
| 101 | db_set("last-sync-url", g.urlCanonical, 0); |
| 102 | if( g.urlPasswd ) db_set("last-sync-pw", g.urlPasswd, 0); |
| 103 | } |
| 104 | if( g.urlUser!=0 && g.urlPasswd==0 ){ |
| 105 | g.urlPasswd = mprintf("%s", zPw); |
| 106 | } |
| 107 | user_select(); |
| 108 | if( g.argc==2 ){ |
| 109 | printf("Server: %s\n", g.urlCanonical); |
| 110 | } |
| 111 | url_enable_proxy("via proxy: "); |
| 112 | } |
| 113 | |
| 114 | /* |
| @@ -189,46 +190,49 @@ | |
| 190 | } |
| 191 | |
| 192 | /* |
| 193 | ** COMMAND: remote-url |
| 194 | ** |
| 195 | ** Usage: %fossil remote-url ?URL|off? |
| 196 | ** |
| 197 | ** Query and/or change the default server URL used by the "pull", "push", |
| 198 | ** and "sync" commands. |
| 199 | ** |
| 200 | ** The remote-url is set automatically by a "clone" command or by any |
| 201 | ** "sync", "push", or "pull" command that specifies an explicit URL. |
| 202 | ** The default remote-url is used by auto-syncing and by "sync", "push", |
| 203 | ** "pull" that omit the server URL. |
| 204 | ** |
| 205 | ** See also: clone, push, pull, sync |
| 206 | */ |
| 207 | void remote_url_cmd(void){ |
| 208 | char *zUrl; |
| 209 | db_find_and_open_repository(1); |
| 210 | if( g.argc!=2 && g.argc!=3 ){ |
| 211 | usage("remote-url ?URL|off?"); |
| 212 | } |
| 213 | if( g.argc==3 ){ |
| 214 | if( strcmp(g.argv[2],"off")==0 ){ |
| 215 | db_unset("last-sync-url", 0); |
| 216 | db_unset("last-sync-pw", 0); |
| 217 | }else{ |
| 218 | url_parse(g.argv[2]); |
| 219 | if( g.urlUser && g.urlPasswd==0 ){ |
| 220 | url_prompt_for_password(); |
| 221 | } |
| 222 | db_set("last-sync-url", g.urlCanonical, 0); |
| 223 | if( g.urlPasswd ){ |
| 224 | db_set("last-sync-pw", g.urlPasswd, 0); |
| 225 | }else{ |
| 226 | db_unset("last-sync-pw", 0); |
| 227 | } |
| 228 | } |
| 229 | } |
| 230 | zUrl = db_get("last-sync-url", 0); |
| 231 | if( zUrl==0 ){ |
| 232 | printf("off\n"); |
| 233 | return; |
| 234 | }else{ |
| 235 | url_parse(zUrl); |
| 236 | printf("%s\n", g.urlCanonical); |
| 237 | } |
| 238 | } |
| 239 |
+26
-5
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -37,11 +37,11 @@ | ||
| 37 | 37 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 38 | 38 | ** g.urlPath Path name for HTTP or HTTPS. |
| 39 | 39 | ** g.urlUser Userid. |
| 40 | 40 | ** g.urlPasswd Password. |
| 41 | 41 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 42 | -** g.urlCanonical The URL in canonical form, omitting userid/password | |
| 42 | +** g.urlCanonical The URL in canonical form, omitting the password | |
| 43 | 43 | ** |
| 44 | 44 | ** HTTP url format is: |
| 45 | 45 | ** |
| 46 | 46 | ** http://userid:password@host:port/path?query#fragment |
| 47 | 47 | ** |
| @@ -49,10 +49,11 @@ | ||
| 49 | 49 | void url_parse(const char *zUrl){ |
| 50 | 50 | int i, j, c; |
| 51 | 51 | char *zFile = 0; |
| 52 | 52 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| 53 | 53 | int iStart; |
| 54 | + char *zLogin; | |
| 54 | 55 | g.urlIsFile = 0; |
| 55 | 56 | if( zUrl[4]=='s' ){ |
| 56 | 57 | g.urlIsHttps = 1; |
| 57 | 58 | g.urlProtocol = "https"; |
| 58 | 59 | g.urlDfltPort = 443; |
| @@ -73,13 +74,15 @@ | ||
| 73 | 74 | dehttpize(g.urlPasswd); |
| 74 | 75 | } |
| 75 | 76 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 76 | 77 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 77 | 78 | i = j; |
| 79 | + zLogin = mprintf("%t@", g.urlUser); | |
| 78 | 80 | }else{ |
| 79 | 81 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 80 | 82 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 83 | + zLogin = mprintf(""); | |
| 81 | 84 | } |
| 82 | 85 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 83 | 86 | if( c==':' ){ |
| 84 | 87 | g.urlPort = 0; |
| 85 | 88 | i++; |
| @@ -94,16 +97,21 @@ | ||
| 94 | 97 | } |
| 95 | 98 | g.urlPath = mprintf(&zUrl[i]); |
| 96 | 99 | dehttpize(g.urlName); |
| 97 | 100 | dehttpize(g.urlPath); |
| 98 | 101 | if( g.urlDfltPort==g.urlPort ){ |
| 99 | - g.urlCanonical = mprintf("%s://%T%T", | |
| 100 | - g.urlProtocol, g.urlName, g.urlPath); | |
| 102 | + g.urlCanonical = mprintf( | |
| 103 | + "%s://%s%T%T", | |
| 104 | + g.urlProtocol, zLogin, g.urlName, g.urlPath | |
| 105 | + ); | |
| 101 | 106 | }else{ |
| 102 | - g.urlCanonical = mprintf("%s://%T:%d%T", | |
| 103 | - g.urlProtocol, g.urlName, g.urlPort, g.urlPath); | |
| 107 | + g.urlCanonical = mprintf( | |
| 108 | + "%s://%s%T:%d%T", | |
| 109 | + g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath | |
| 110 | + ); | |
| 104 | 111 | } |
| 112 | + free(zLogin); | |
| 105 | 113 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 106 | 114 | g.urlIsFile = 1; |
| 107 | 115 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 108 | 116 | i = 7; |
| 109 | 117 | }else{ |
| @@ -296,5 +304,18 @@ | ||
| 296 | 304 | if( zName2 && zValue2 ){ |
| 297 | 305 | blob_appendf(&p->url, "%s%s=%T", zSep, zName2, zValue2); |
| 298 | 306 | } |
| 299 | 307 | return blob_str(&p->url); |
| 300 | 308 | } |
| 309 | + | |
| 310 | +/* | |
| 311 | +** Prompt the user for the password for g.urlUser. Store the result | |
| 312 | +** in g.urlPasswd. | |
| 313 | +*/ | |
| 314 | +void url_prompt_for_password(void){ | |
| 315 | + char *zPrompt = mprintf("password for %s: ", g.urlUser); | |
| 316 | + Blob x; | |
| 317 | + prompt_for_password(zPrompt, &x, 0); | |
| 318 | + free(zPrompt); | |
| 319 | + g.urlPasswd = mprintf("%b", &x); | |
| 320 | + blob_reset(&x); | |
| 321 | +} | |
| 301 | 322 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -37,11 +37,11 @@ | |
| 37 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 38 | ** g.urlPath Path name for HTTP or HTTPS. |
| 39 | ** g.urlUser Userid. |
| 40 | ** g.urlPasswd Password. |
| 41 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 42 | ** g.urlCanonical The URL in canonical form, omitting userid/password |
| 43 | ** |
| 44 | ** HTTP url format is: |
| 45 | ** |
| 46 | ** http://userid:password@host:port/path?query#fragment |
| 47 | ** |
| @@ -49,10 +49,11 @@ | |
| 49 | void url_parse(const char *zUrl){ |
| 50 | int i, j, c; |
| 51 | char *zFile = 0; |
| 52 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| 53 | int iStart; |
| 54 | g.urlIsFile = 0; |
| 55 | if( zUrl[4]=='s' ){ |
| 56 | g.urlIsHttps = 1; |
| 57 | g.urlProtocol = "https"; |
| 58 | g.urlDfltPort = 443; |
| @@ -73,13 +74,15 @@ | |
| 73 | dehttpize(g.urlPasswd); |
| 74 | } |
| 75 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 76 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 77 | i = j; |
| 78 | }else{ |
| 79 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 80 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 81 | } |
| 82 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 83 | if( c==':' ){ |
| 84 | g.urlPort = 0; |
| 85 | i++; |
| @@ -94,16 +97,21 @@ | |
| 94 | } |
| 95 | g.urlPath = mprintf(&zUrl[i]); |
| 96 | dehttpize(g.urlName); |
| 97 | dehttpize(g.urlPath); |
| 98 | if( g.urlDfltPort==g.urlPort ){ |
| 99 | g.urlCanonical = mprintf("%s://%T%T", |
| 100 | g.urlProtocol, g.urlName, g.urlPath); |
| 101 | }else{ |
| 102 | g.urlCanonical = mprintf("%s://%T:%d%T", |
| 103 | g.urlProtocol, g.urlName, g.urlPort, g.urlPath); |
| 104 | } |
| 105 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 106 | g.urlIsFile = 1; |
| 107 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 108 | i = 7; |
| 109 | }else{ |
| @@ -296,5 +304,18 @@ | |
| 296 | if( zName2 && zValue2 ){ |
| 297 | blob_appendf(&p->url, "%s%s=%T", zSep, zName2, zValue2); |
| 298 | } |
| 299 | return blob_str(&p->url); |
| 300 | } |
| 301 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -37,11 +37,11 @@ | |
| 37 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 38 | ** g.urlPath Path name for HTTP or HTTPS. |
| 39 | ** g.urlUser Userid. |
| 40 | ** g.urlPasswd Password. |
| 41 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 42 | ** g.urlCanonical The URL in canonical form, omitting the password |
| 43 | ** |
| 44 | ** HTTP url format is: |
| 45 | ** |
| 46 | ** http://userid:password@host:port/path?query#fragment |
| 47 | ** |
| @@ -49,10 +49,11 @@ | |
| 49 | void url_parse(const char *zUrl){ |
| 50 | int i, j, c; |
| 51 | char *zFile = 0; |
| 52 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| 53 | int iStart; |
| 54 | char *zLogin; |
| 55 | g.urlIsFile = 0; |
| 56 | if( zUrl[4]=='s' ){ |
| 57 | g.urlIsHttps = 1; |
| 58 | g.urlProtocol = "https"; |
| 59 | g.urlDfltPort = 443; |
| @@ -73,13 +74,15 @@ | |
| 74 | dehttpize(g.urlPasswd); |
| 75 | } |
| 76 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 77 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 78 | i = j; |
| 79 | zLogin = mprintf("%t@", g.urlUser); |
| 80 | }else{ |
| 81 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 82 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 83 | zLogin = mprintf(""); |
| 84 | } |
| 85 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 86 | if( c==':' ){ |
| 87 | g.urlPort = 0; |
| 88 | i++; |
| @@ -94,16 +97,21 @@ | |
| 97 | } |
| 98 | g.urlPath = mprintf(&zUrl[i]); |
| 99 | dehttpize(g.urlName); |
| 100 | dehttpize(g.urlPath); |
| 101 | if( g.urlDfltPort==g.urlPort ){ |
| 102 | g.urlCanonical = mprintf( |
| 103 | "%s://%s%T%T", |
| 104 | g.urlProtocol, zLogin, g.urlName, g.urlPath |
| 105 | ); |
| 106 | }else{ |
| 107 | g.urlCanonical = mprintf( |
| 108 | "%s://%s%T:%d%T", |
| 109 | g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath |
| 110 | ); |
| 111 | } |
| 112 | free(zLogin); |
| 113 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 114 | g.urlIsFile = 1; |
| 115 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 116 | i = 7; |
| 117 | }else{ |
| @@ -296,5 +304,18 @@ | |
| 304 | if( zName2 && zValue2 ){ |
| 305 | blob_appendf(&p->url, "%s%s=%T", zSep, zName2, zValue2); |
| 306 | } |
| 307 | return blob_str(&p->url); |
| 308 | } |
| 309 | |
| 310 | /* |
| 311 | ** Prompt the user for the password for g.urlUser. Store the result |
| 312 | ** in g.urlPasswd. |
| 313 | */ |
| 314 | void url_prompt_for_password(void){ |
| 315 | char *zPrompt = mprintf("password for %s: ", g.urlUser); |
| 316 | Blob x; |
| 317 | prompt_for_password(zPrompt, &x, 0); |
| 318 | free(zPrompt); |
| 319 | g.urlPasswd = mprintf("%b", &x); |
| 320 | blob_reset(&x); |
| 321 | } |
| 322 |
+29
-11
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -342,12 +342,11 @@ | ||
| 342 | 342 | db_finalize(&q); |
| 343 | 343 | } |
| 344 | 344 | |
| 345 | 345 | /* |
| 346 | 346 | ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the |
| 347 | -** the hash given in pHash. Return 1 on a successful match. Return 0 | |
| 348 | -** if there is a mismatch. | |
| 347 | +** the hash given in pHash. Return non-zero for an error and 0 on success. | |
| 349 | 348 | */ |
| 350 | 349 | static int check_tail_hash(Blob *pHash, Blob *pMsg){ |
| 351 | 350 | Blob tail; |
| 352 | 351 | Blob h2; |
| 353 | 352 | int rc; |
| @@ -354,11 +353,11 @@ | ||
| 354 | 353 | blob_tail(pMsg, &tail); |
| 355 | 354 | sha1sum_blob(&tail, &h2); |
| 356 | 355 | rc = blob_compare(pHash, &h2); |
| 357 | 356 | blob_reset(&h2); |
| 358 | 357 | blob_reset(&tail); |
| 359 | - return rc==0; | |
| 358 | + return rc; | |
| 360 | 359 | } |
| 361 | 360 | |
| 362 | 361 | /* |
| 363 | 362 | ** Check the signature on an application/x-fossil payload received by |
| 364 | 363 | ** the HTTP server. The signature is a line of the following form: |
| @@ -378,12 +377,14 @@ | ||
| 378 | 377 | ** |
| 379 | 378 | ** If anything fails to check out, no changes are made to privileges. |
| 380 | 379 | ** |
| 381 | 380 | ** Signature generation on the client side is handled by the |
| 382 | 381 | ** http_exchange() routine. |
| 382 | +** | |
| 383 | +** Return non-zero for a login failure and zero for success. | |
| 383 | 384 | */ |
| 384 | -void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ | |
| 385 | +int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ | |
| 385 | 386 | Stmt q; |
| 386 | 387 | int rc = -1; |
| 387 | 388 | char *zLogin = blob_terminate(pLogin); |
| 388 | 389 | defossilize(zLogin); |
| 389 | 390 | |
| @@ -440,10 +441,11 @@ | ||
| 440 | 441 | |
| 441 | 442 | if( rc==0 ){ |
| 442 | 443 | /* If the login was successful. */ |
| 443 | 444 | login_set_anon_nobody_capabilities(); |
| 444 | 445 | } |
| 446 | + return rc; | |
| 445 | 447 | } |
| 446 | 448 | |
| 447 | 449 | /* |
| 448 | 450 | ** Send the content of all files in the unsent table. |
| 449 | 451 | ** |
| @@ -741,12 +743,19 @@ | ||
| 741 | 743 | if( blob_eq(&xfer.aToken[0], "login") |
| 742 | 744 | && xfer.nToken==4 |
| 743 | 745 | ){ |
| 744 | 746 | if( disableLogin ){ |
| 745 | 747 | g.okRead = g.okWrite = 1; |
| 746 | - }else if( check_tail_hash(&xfer.aToken[2], xfer.pIn) ){ | |
| 747 | - check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]); | |
| 748 | + }else{ | |
| 749 | + if( check_tail_hash(&xfer.aToken[2], xfer.pIn) | |
| 750 | + || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) | |
| 751 | + ){ | |
| 752 | + cgi_reset_content(); | |
| 753 | + @ error login\sfailed | |
| 754 | + nErr++; | |
| 755 | + break; | |
| 756 | + } | |
| 748 | 757 | } |
| 749 | 758 | }else |
| 750 | 759 | |
| 751 | 760 | /* reqconfig NAME |
| 752 | 761 | ** |
| @@ -1067,10 +1076,11 @@ | ||
| 1067 | 1076 | } |
| 1068 | 1077 | if( pushFlag ){ |
| 1069 | 1078 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 1070 | 1079 | nCardSent++; |
| 1071 | 1080 | } |
| 1081 | + go = 0; | |
| 1072 | 1082 | |
| 1073 | 1083 | /* Process the reply that came back from the server */ |
| 1074 | 1084 | while( blob_line(&recv, &xfer.line) ){ |
| 1075 | 1085 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 1076 | 1086 | continue; |
| @@ -1208,16 +1218,19 @@ | ||
| 1208 | 1218 | db_set("cookie", blob_str(&xfer.aToken[1]), 0); |
| 1209 | 1219 | }else |
| 1210 | 1220 | |
| 1211 | 1221 | /* message MESSAGE |
| 1212 | 1222 | ** |
| 1213 | - ** Print a message. Similar to "error" but does not stop processing | |
| 1223 | + ** Print a message. Similar to "error" but does not stop processing. | |
| 1224 | + ** | |
| 1225 | + ** If the "login failed" message is seen, clear the sync password prior | |
| 1226 | + ** to the next cycle. | |
| 1214 | 1227 | */ |
| 1215 | 1228 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1216 | 1229 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1217 | 1230 | defossilize(zMsg); |
| 1218 | - printf("\rServer says: %s\n", zMsg); | |
| 1231 | + if( zMsg ) printf("\rServer says: %s\n", zMsg); | |
| 1219 | 1232 | }else |
| 1220 | 1233 | |
| 1221 | 1234 | /* error MESSAGE |
| 1222 | 1235 | ** |
| 1223 | 1236 | ** Report an error and abandon the sync session. |
| @@ -1231,12 +1244,18 @@ | ||
| 1231 | 1244 | */ |
| 1232 | 1245 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1233 | 1246 | if( !cloneFlag || nCycle>0 ){ |
| 1234 | 1247 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1235 | 1248 | defossilize(zMsg); |
| 1236 | - blob_appendf(&xfer.err, "server says: %s", zMsg); | |
| 1237 | - printf("Server Error: %s\n", zMsg); | |
| 1249 | + if( strcmp(zMsg, "login failed")==0 ){ | |
| 1250 | + if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0); | |
| 1251 | + g.urlPasswd = 0; | |
| 1252 | + if( nCycle<2 ) go = 1; | |
| 1253 | + }else{ | |
| 1254 | + blob_appendf(&xfer.err, "\rserver says: %s", zMsg); | |
| 1255 | + } | |
| 1256 | + printf("\rServer Error: %s\n", zMsg); | |
| 1238 | 1257 | } |
| 1239 | 1258 | }else |
| 1240 | 1259 | |
| 1241 | 1260 | /* Unknown message */ |
| 1242 | 1261 | { |
| @@ -1264,11 +1283,10 @@ | ||
| 1264 | 1283 | blob_size(&recv), nCardRcvd, |
| 1265 | 1284 | xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); |
| 1266 | 1285 | } |
| 1267 | 1286 | blob_reset(&recv); |
| 1268 | 1287 | nCycle++; |
| 1269 | - go = 0; | |
| 1270 | 1288 | |
| 1271 | 1289 | /* If we received one or more files on the previous exchange but |
| 1272 | 1290 | ** there are still phantoms, then go another round. |
| 1273 | 1291 | */ |
| 1274 | 1292 | nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; |
| 1275 | 1293 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -342,12 +342,11 @@ | |
| 342 | db_finalize(&q); |
| 343 | } |
| 344 | |
| 345 | /* |
| 346 | ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the |
| 347 | ** the hash given in pHash. Return 1 on a successful match. Return 0 |
| 348 | ** if there is a mismatch. |
| 349 | */ |
| 350 | static int check_tail_hash(Blob *pHash, Blob *pMsg){ |
| 351 | Blob tail; |
| 352 | Blob h2; |
| 353 | int rc; |
| @@ -354,11 +353,11 @@ | |
| 354 | blob_tail(pMsg, &tail); |
| 355 | sha1sum_blob(&tail, &h2); |
| 356 | rc = blob_compare(pHash, &h2); |
| 357 | blob_reset(&h2); |
| 358 | blob_reset(&tail); |
| 359 | return rc==0; |
| 360 | } |
| 361 | |
| 362 | /* |
| 363 | ** Check the signature on an application/x-fossil payload received by |
| 364 | ** the HTTP server. The signature is a line of the following form: |
| @@ -378,12 +377,14 @@ | |
| 378 | ** |
| 379 | ** If anything fails to check out, no changes are made to privileges. |
| 380 | ** |
| 381 | ** Signature generation on the client side is handled by the |
| 382 | ** http_exchange() routine. |
| 383 | */ |
| 384 | void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ |
| 385 | Stmt q; |
| 386 | int rc = -1; |
| 387 | char *zLogin = blob_terminate(pLogin); |
| 388 | defossilize(zLogin); |
| 389 | |
| @@ -440,10 +441,11 @@ | |
| 440 | |
| 441 | if( rc==0 ){ |
| 442 | /* If the login was successful. */ |
| 443 | login_set_anon_nobody_capabilities(); |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | /* |
| 448 | ** Send the content of all files in the unsent table. |
| 449 | ** |
| @@ -741,12 +743,19 @@ | |
| 741 | if( blob_eq(&xfer.aToken[0], "login") |
| 742 | && xfer.nToken==4 |
| 743 | ){ |
| 744 | if( disableLogin ){ |
| 745 | g.okRead = g.okWrite = 1; |
| 746 | }else if( check_tail_hash(&xfer.aToken[2], xfer.pIn) ){ |
| 747 | check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]); |
| 748 | } |
| 749 | }else |
| 750 | |
| 751 | /* reqconfig NAME |
| 752 | ** |
| @@ -1067,10 +1076,11 @@ | |
| 1067 | } |
| 1068 | if( pushFlag ){ |
| 1069 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 1070 | nCardSent++; |
| 1071 | } |
| 1072 | |
| 1073 | /* Process the reply that came back from the server */ |
| 1074 | while( blob_line(&recv, &xfer.line) ){ |
| 1075 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 1076 | continue; |
| @@ -1208,16 +1218,19 @@ | |
| 1208 | db_set("cookie", blob_str(&xfer.aToken[1]), 0); |
| 1209 | }else |
| 1210 | |
| 1211 | /* message MESSAGE |
| 1212 | ** |
| 1213 | ** Print a message. Similar to "error" but does not stop processing |
| 1214 | */ |
| 1215 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1216 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1217 | defossilize(zMsg); |
| 1218 | printf("\rServer says: %s\n", zMsg); |
| 1219 | }else |
| 1220 | |
| 1221 | /* error MESSAGE |
| 1222 | ** |
| 1223 | ** Report an error and abandon the sync session. |
| @@ -1231,12 +1244,18 @@ | |
| 1231 | */ |
| 1232 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1233 | if( !cloneFlag || nCycle>0 ){ |
| 1234 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1235 | defossilize(zMsg); |
| 1236 | blob_appendf(&xfer.err, "server says: %s", zMsg); |
| 1237 | printf("Server Error: %s\n", zMsg); |
| 1238 | } |
| 1239 | }else |
| 1240 | |
| 1241 | /* Unknown message */ |
| 1242 | { |
| @@ -1264,11 +1283,10 @@ | |
| 1264 | blob_size(&recv), nCardRcvd, |
| 1265 | xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); |
| 1266 | } |
| 1267 | blob_reset(&recv); |
| 1268 | nCycle++; |
| 1269 | go = 0; |
| 1270 | |
| 1271 | /* If we received one or more files on the previous exchange but |
| 1272 | ** there are still phantoms, then go another round. |
| 1273 | */ |
| 1274 | nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; |
| 1275 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -342,12 +342,11 @@ | |
| 342 | db_finalize(&q); |
| 343 | } |
| 344 | |
| 345 | /* |
| 346 | ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the |
| 347 | ** the hash given in pHash. Return non-zero for an error and 0 on success. |
| 348 | */ |
| 349 | static int check_tail_hash(Blob *pHash, Blob *pMsg){ |
| 350 | Blob tail; |
| 351 | Blob h2; |
| 352 | int rc; |
| @@ -354,11 +353,11 @@ | |
| 353 | blob_tail(pMsg, &tail); |
| 354 | sha1sum_blob(&tail, &h2); |
| 355 | rc = blob_compare(pHash, &h2); |
| 356 | blob_reset(&h2); |
| 357 | blob_reset(&tail); |
| 358 | return rc; |
| 359 | } |
| 360 | |
| 361 | /* |
| 362 | ** Check the signature on an application/x-fossil payload received by |
| 363 | ** the HTTP server. The signature is a line of the following form: |
| @@ -378,12 +377,14 @@ | |
| 377 | ** |
| 378 | ** If anything fails to check out, no changes are made to privileges. |
| 379 | ** |
| 380 | ** Signature generation on the client side is handled by the |
| 381 | ** http_exchange() routine. |
| 382 | ** |
| 383 | ** Return non-zero for a login failure and zero for success. |
| 384 | */ |
| 385 | int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ |
| 386 | Stmt q; |
| 387 | int rc = -1; |
| 388 | char *zLogin = blob_terminate(pLogin); |
| 389 | defossilize(zLogin); |
| 390 | |
| @@ -440,10 +441,11 @@ | |
| 441 | |
| 442 | if( rc==0 ){ |
| 443 | /* If the login was successful. */ |
| 444 | login_set_anon_nobody_capabilities(); |
| 445 | } |
| 446 | return rc; |
| 447 | } |
| 448 | |
| 449 | /* |
| 450 | ** Send the content of all files in the unsent table. |
| 451 | ** |
| @@ -741,12 +743,19 @@ | |
| 743 | if( blob_eq(&xfer.aToken[0], "login") |
| 744 | && xfer.nToken==4 |
| 745 | ){ |
| 746 | if( disableLogin ){ |
| 747 | g.okRead = g.okWrite = 1; |
| 748 | }else{ |
| 749 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) |
| 750 | || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) |
| 751 | ){ |
| 752 | cgi_reset_content(); |
| 753 | @ error login\sfailed |
| 754 | nErr++; |
| 755 | break; |
| 756 | } |
| 757 | } |
| 758 | }else |
| 759 | |
| 760 | /* reqconfig NAME |
| 761 | ** |
| @@ -1067,10 +1076,11 @@ | |
| 1076 | } |
| 1077 | if( pushFlag ){ |
| 1078 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 1079 | nCardSent++; |
| 1080 | } |
| 1081 | go = 0; |
| 1082 | |
| 1083 | /* Process the reply that came back from the server */ |
| 1084 | while( blob_line(&recv, &xfer.line) ){ |
| 1085 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 1086 | continue; |
| @@ -1208,16 +1218,19 @@ | |
| 1218 | db_set("cookie", blob_str(&xfer.aToken[1]), 0); |
| 1219 | }else |
| 1220 | |
| 1221 | /* message MESSAGE |
| 1222 | ** |
| 1223 | ** Print a message. Similar to "error" but does not stop processing. |
| 1224 | ** |
| 1225 | ** If the "login failed" message is seen, clear the sync password prior |
| 1226 | ** to the next cycle. |
| 1227 | */ |
| 1228 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1229 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1230 | defossilize(zMsg); |
| 1231 | if( zMsg ) printf("\rServer says: %s\n", zMsg); |
| 1232 | }else |
| 1233 | |
| 1234 | /* error MESSAGE |
| 1235 | ** |
| 1236 | ** Report an error and abandon the sync session. |
| @@ -1231,12 +1244,18 @@ | |
| 1244 | */ |
| 1245 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1246 | if( !cloneFlag || nCycle>0 ){ |
| 1247 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1248 | defossilize(zMsg); |
| 1249 | if( strcmp(zMsg, "login failed")==0 ){ |
| 1250 | if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0); |
| 1251 | g.urlPasswd = 0; |
| 1252 | if( nCycle<2 ) go = 1; |
| 1253 | }else{ |
| 1254 | blob_appendf(&xfer.err, "\rserver says: %s", zMsg); |
| 1255 | } |
| 1256 | printf("\rServer Error: %s\n", zMsg); |
| 1257 | } |
| 1258 | }else |
| 1259 | |
| 1260 | /* Unknown message */ |
| 1261 | { |
| @@ -1264,11 +1283,10 @@ | |
| 1283 | blob_size(&recv), nCardRcvd, |
| 1284 | xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); |
| 1285 | } |
| 1286 | blob_reset(&recv); |
| 1287 | nCycle++; |
| 1288 | |
| 1289 | /* If we received one or more files on the previous exchange but |
| 1290 | ** there are still phantoms, then go another round. |
| 1291 | */ |
| 1292 | nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; |
| 1293 |