Fossil SCM
Use POST instead of GET for the /xfer method. Other bug fixes in the URL parser.
Commit
e621b6dbe310661d111e8caba43bdac40fd9693b
Parent
396cc2a4eb1e99b…
6 files changed
+20
-5
+13
-9
+2
+38
-3
+9
-5
+2
+20
-5
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -157,19 +157,34 @@ | ||
| 157 | 157 | Blob login, nonce, sig, pw, payload, hdr; |
| 158 | 158 | const char *zSep; |
| 159 | 159 | int i; |
| 160 | 160 | int cnt = 0; |
| 161 | 161 | |
| 162 | - user_select(); | |
| 163 | 162 | blob_zero(&nonce); |
| 164 | 163 | blob_zero(&pw); |
| 165 | 164 | db_blob(&nonce, "SELECT hex(randomblob(20))"); |
| 166 | 165 | blob_copy(&pw, &nonce); |
| 167 | - db_blob(&pw, "SELECT pw FROM user WHERE uid=%d", g.userUid); | |
| 168 | - sha1sum_blob(&pw, &sig); | |
| 169 | 166 | blob_zero(&login); |
| 170 | - blob_appendf(&login, "login %s %b %b\n", g.zLogin, &nonce, &sig); | |
| 167 | + if( g.urlUser==0 ){ | |
| 168 | + user_select(); | |
| 169 | + db_blob(&pw, "SELECT pw FROM user WHERE uid=%d", g.userUid); | |
| 170 | + sha1sum_blob(&pw, &sig); | |
| 171 | + blob_appendf(&login, "login %s %b %b\n", g.zLogin, &nonce, &sig); | |
| 172 | + }else{ | |
| 173 | + if( g.urlPasswd==0 ){ | |
| 174 | + if( strcmp(g.urlUser,"anonymous")!=0 ){ | |
| 175 | + char *zPrompt = mprintf("password for %s", g.urlUser); | |
| 176 | + Blob x; | |
| 177 | + prompt_for_password(zPrompt, &x, 0); | |
| 178 | + free(zPrompt); | |
| 179 | + blob_append(&pw, blob_buffer(&x), blob_size(&x)); | |
| 180 | + blob_reset(&x); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + sha1sum_blob(&pw, &sig); | |
| 184 | + blob_appendf(&login, "login %s %b %b\n", g.urlUser, &nonce, &sig); | |
| 185 | + } | |
| 171 | 186 | blob_reset(&nonce); |
| 172 | 187 | blob_reset(&pw); |
| 173 | 188 | blob_reset(&sig); |
| 174 | 189 | if( g.fHttpTrace ){ |
| 175 | 190 | payload = login; |
| @@ -183,11 +198,11 @@ | ||
| 183 | 198 | if( i>0 && g.urlPath[i-1]=='/' ){ |
| 184 | 199 | zSep = ""; |
| 185 | 200 | }else{ |
| 186 | 201 | zSep = "/"; |
| 187 | 202 | } |
| 188 | - blob_appendf(&hdr, "GET %s%sxfer HTTP/1.1\r\n", g.urlPath, zSep); | |
| 203 | + blob_appendf(&hdr, "POST %s%sxfer HTTP/1.1\r\n", g.urlPath, zSep); | |
| 189 | 204 | if( g.fHttpTrace ){ |
| 190 | 205 | blob_appendf(&hdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 191 | 206 | }else{ |
| 192 | 207 | blob_appendf(&hdr, "Content-Type: application/x-fossil\r\n"); |
| 193 | 208 | } |
| 194 | 209 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -157,19 +157,34 @@ | |
| 157 | Blob login, nonce, sig, pw, payload, hdr; |
| 158 | const char *zSep; |
| 159 | int i; |
| 160 | int cnt = 0; |
| 161 | |
| 162 | user_select(); |
| 163 | blob_zero(&nonce); |
| 164 | blob_zero(&pw); |
| 165 | db_blob(&nonce, "SELECT hex(randomblob(20))"); |
| 166 | blob_copy(&pw, &nonce); |
| 167 | db_blob(&pw, "SELECT pw FROM user WHERE uid=%d", g.userUid); |
| 168 | sha1sum_blob(&pw, &sig); |
| 169 | blob_zero(&login); |
| 170 | blob_appendf(&login, "login %s %b %b\n", g.zLogin, &nonce, &sig); |
| 171 | blob_reset(&nonce); |
| 172 | blob_reset(&pw); |
| 173 | blob_reset(&sig); |
| 174 | if( g.fHttpTrace ){ |
| 175 | payload = login; |
| @@ -183,11 +198,11 @@ | |
| 183 | if( i>0 && g.urlPath[i-1]=='/' ){ |
| 184 | zSep = ""; |
| 185 | }else{ |
| 186 | zSep = "/"; |
| 187 | } |
| 188 | blob_appendf(&hdr, "GET %s%sxfer HTTP/1.1\r\n", g.urlPath, zSep); |
| 189 | if( g.fHttpTrace ){ |
| 190 | blob_appendf(&hdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 191 | }else{ |
| 192 | blob_appendf(&hdr, "Content-Type: application/x-fossil\r\n"); |
| 193 | } |
| 194 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -157,19 +157,34 @@ | |
| 157 | Blob login, nonce, sig, pw, payload, hdr; |
| 158 | const char *zSep; |
| 159 | int i; |
| 160 | int cnt = 0; |
| 161 | |
| 162 | blob_zero(&nonce); |
| 163 | blob_zero(&pw); |
| 164 | db_blob(&nonce, "SELECT hex(randomblob(20))"); |
| 165 | blob_copy(&pw, &nonce); |
| 166 | blob_zero(&login); |
| 167 | if( g.urlUser==0 ){ |
| 168 | user_select(); |
| 169 | db_blob(&pw, "SELECT pw FROM user WHERE uid=%d", g.userUid); |
| 170 | sha1sum_blob(&pw, &sig); |
| 171 | blob_appendf(&login, "login %s %b %b\n", g.zLogin, &nonce, &sig); |
| 172 | }else{ |
| 173 | if( g.urlPasswd==0 ){ |
| 174 | if( strcmp(g.urlUser,"anonymous")!=0 ){ |
| 175 | char *zPrompt = mprintf("password for %s", g.urlUser); |
| 176 | Blob x; |
| 177 | prompt_for_password(zPrompt, &x, 0); |
| 178 | free(zPrompt); |
| 179 | blob_append(&pw, blob_buffer(&x), blob_size(&x)); |
| 180 | blob_reset(&x); |
| 181 | } |
| 182 | } |
| 183 | sha1sum_blob(&pw, &sig); |
| 184 | blob_appendf(&login, "login %s %b %b\n", g.urlUser, &nonce, &sig); |
| 185 | } |
| 186 | blob_reset(&nonce); |
| 187 | blob_reset(&pw); |
| 188 | blob_reset(&sig); |
| 189 | if( g.fHttpTrace ){ |
| 190 | payload = login; |
| @@ -183,11 +198,11 @@ | |
| 198 | if( i>0 && g.urlPath[i-1]=='/' ){ |
| 199 | zSep = ""; |
| 200 | }else{ |
| 201 | zSep = "/"; |
| 202 | } |
| 203 | blob_appendf(&hdr, "POST %s%sxfer HTTP/1.1\r\n", g.urlPath, zSep); |
| 204 | if( g.fHttpTrace ){ |
| 205 | blob_appendf(&hdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 206 | }else{ |
| 207 | blob_appendf(&hdr, "Content-Type: application/x-fossil\r\n"); |
| 208 | } |
| 209 |
+13
-9
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -203,19 +203,23 @@ | ||
| 203 | 203 | g.isAnon = 0; |
| 204 | 204 | } |
| 205 | 205 | |
| 206 | 206 | /* Check the login cookie to see if it matches a known valid user. |
| 207 | 207 | */ |
| 208 | - if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){ | |
| 209 | - uid = db_int(0, | |
| 210 | - "SELECT 1 FROM user" | |
| 211 | - " WHERE uid=%d" | |
| 212 | - " AND cookie=%Q" | |
| 213 | - " AND ipaddr=%Q" | |
| 214 | - " AND cexpire>julianday('now')", | |
| 215 | - atoi(zCookie), zCookie, zRemoteAddr | |
| 216 | - ); | |
| 208 | + if( uid==0 ){ | |
| 209 | + if( (zCookie = P(login_cookie_name()))!=0 ){ | |
| 210 | + uid = db_int(0, | |
| 211 | + "SELECT uid FROM user" | |
| 212 | + " WHERE uid=%d" | |
| 213 | + " AND cookie=%Q" | |
| 214 | + " AND ipaddr=%Q" | |
| 215 | + " AND cexpire>julianday('now')", | |
| 216 | + atoi(zCookie), zCookie, zRemoteAddr | |
| 217 | + ); | |
| 218 | + }else{ | |
| 219 | + uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"); | |
| 220 | + } | |
| 217 | 221 | } |
| 218 | 222 | |
| 219 | 223 | if( uid==0 ){ |
| 220 | 224 | g.isAnon = 1; |
| 221 | 225 | g.zLogin = ""; |
| 222 | 226 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -203,19 +203,23 @@ | |
| 203 | g.isAnon = 0; |
| 204 | } |
| 205 | |
| 206 | /* Check the login cookie to see if it matches a known valid user. |
| 207 | */ |
| 208 | if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){ |
| 209 | uid = db_int(0, |
| 210 | "SELECT 1 FROM user" |
| 211 | " WHERE uid=%d" |
| 212 | " AND cookie=%Q" |
| 213 | " AND ipaddr=%Q" |
| 214 | " AND cexpire>julianday('now')", |
| 215 | atoi(zCookie), zCookie, zRemoteAddr |
| 216 | ); |
| 217 | } |
| 218 | |
| 219 | if( uid==0 ){ |
| 220 | g.isAnon = 1; |
| 221 | g.zLogin = ""; |
| 222 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -203,19 +203,23 @@ | |
| 203 | g.isAnon = 0; |
| 204 | } |
| 205 | |
| 206 | /* Check the login cookie to see if it matches a known valid user. |
| 207 | */ |
| 208 | if( uid==0 ){ |
| 209 | if( (zCookie = P(login_cookie_name()))!=0 ){ |
| 210 | uid = db_int(0, |
| 211 | "SELECT uid FROM user" |
| 212 | " WHERE uid=%d" |
| 213 | " AND cookie=%Q" |
| 214 | " AND ipaddr=%Q" |
| 215 | " AND cexpire>julianday('now')", |
| 216 | atoi(zCookie), zCookie, zRemoteAddr |
| 217 | ); |
| 218 | }else{ |
| 219 | uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | if( uid==0 ){ |
| 224 | g.isAnon = 1; |
| 225 | g.zLogin = ""; |
| 226 |
+2
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -69,10 +69,12 @@ | ||
| 69 | 69 | |
| 70 | 70 | int urlIsFile; /* True if a "file:" url */ |
| 71 | 71 | char *urlName; /* Hostname for http: or filename for file: */ |
| 72 | 72 | int urlPort; /* TCP port number for http: */ |
| 73 | 73 | char *urlPath; /* Pathname for http: */ |
| 74 | + char *urlUser; /* User id for http: */ | |
| 75 | + char *urlPasswd; /* Password for http: */ | |
| 74 | 76 | char *urlCanonical; /* Canonical representation of the URL */ |
| 75 | 77 | |
| 76 | 78 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 77 | 79 | int isAnon; /* True if logged in anoymously */ |
| 78 | 80 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 79 | 81 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -69,10 +69,12 @@ | |
| 69 | |
| 70 | int urlIsFile; /* True if a "file:" url */ |
| 71 | char *urlName; /* Hostname for http: or filename for file: */ |
| 72 | int urlPort; /* TCP port number for http: */ |
| 73 | char *urlPath; /* Pathname for http: */ |
| 74 | char *urlCanonical; /* Canonical representation of the URL */ |
| 75 | |
| 76 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 77 | int isAnon; /* True if logged in anoymously */ |
| 78 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 79 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -69,10 +69,12 @@ | |
| 69 | |
| 70 | int urlIsFile; /* True if a "file:" url */ |
| 71 | char *urlName; /* Hostname for http: or filename for file: */ |
| 72 | int urlPort; /* TCP port number for http: */ |
| 73 | char *urlPath; /* Pathname for http: */ |
| 74 | char *urlUser; /* User id for http: */ |
| 75 | char *urlPasswd; /* Password for http: */ |
| 76 | char *urlCanonical; /* Canonical representation of the URL */ |
| 77 | |
| 78 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 79 | int isAnon; /* True if logged in anoymously */ |
| 80 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 81 |
+38
-3
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -31,20 +31,38 @@ | ||
| 31 | 31 | ** |
| 32 | 32 | ** g.urlIsFile True if this is a file URL |
| 33 | 33 | ** g.urlName Hostname for HTTP:. Filename for FILE: |
| 34 | 34 | ** g.urlPort Port name for HTTP. |
| 35 | 35 | ** g.urlPath Path name for HTTP. |
| 36 | +** g.urlUser Userid. | |
| 37 | +** g.urlPasswd Password. | |
| 36 | 38 | ** g.urlCanonical The URL in canonical form |
| 37 | 39 | ** |
| 40 | +** HTTP url format is: | |
| 41 | +** | |
| 42 | +** http://userid:password@host:port/path?query#fragment | |
| 43 | +** | |
| 38 | 44 | */ |
| 39 | 45 | void url_parse(const char *zUrl){ |
| 40 | 46 | int i, j, c; |
| 41 | - char *zFile; | |
| 47 | + char *zFile = 0; | |
| 42 | 48 | if( strncmp(zUrl, "http:", 5)==0 ){ |
| 43 | 49 | g.urlIsFile = 0; |
| 44 | - for(i=7; (c=zUrl[i])!=0 && c!=':' && c!='/'; i++){} | |
| 45 | - g.urlName = mprintf("%.*s", i-7, &zUrl[7]); | |
| 50 | + for(i=7; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){} | |
| 51 | + if( c=='@' ){ | |
| 52 | + for(j=7; j<i && zUrl[j]!=':'; j++){} | |
| 53 | + g.urlUser = mprintf("%.*s", j-7, &zUrl[7]); | |
| 54 | + if( j<i ){ | |
| 55 | + g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]); | |
| 56 | + } | |
| 57 | + for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} | |
| 58 | + g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); | |
| 59 | + i = j; | |
| 60 | + }else{ | |
| 61 | + for(i=7; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} | |
| 62 | + g.urlName = mprintf("%.*s", i-7, &zUrl[7]); | |
| 63 | + } | |
| 46 | 64 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 47 | 65 | if( c==':' ){ |
| 48 | 66 | g.urlPort = 0; |
| 49 | 67 | i++; |
| 50 | 68 | while( (c = zUrl[i])!=0 && isdigit(c) ){ |
| @@ -88,5 +106,22 @@ | ||
| 88 | 106 | g.urlName = mprintf("%b", &cfile); |
| 89 | 107 | g.urlCanonical = mprintf("file://%T", g.urlName); |
| 90 | 108 | blob_reset(&cfile); |
| 91 | 109 | } |
| 92 | 110 | } |
| 111 | + | |
| 112 | +/* | |
| 113 | +** COMMAND: test-urlparser | |
| 114 | +*/ | |
| 115 | +void cmd_test_urlparser(void){ | |
| 116 | + if( g.argc!=3 ){ | |
| 117 | + usage("URL"); | |
| 118 | + } | |
| 119 | + url_parse(g.argv[2]); | |
| 120 | + printf("g.urlIsFile = %d\n", g.urlIsFile); | |
| 121 | + printf("g.urlName = %s\n", g.urlName); | |
| 122 | + printf("g.urlPort = %d\n", g.urlPort); | |
| 123 | + printf("g.urlPath = %s\n", g.urlPath); | |
| 124 | + printf("g.urlUser = %s\n", g.urlUser); | |
| 125 | + printf("g.urlPasswd = %s\n", g.urlPasswd); | |
| 126 | + printf("g.urlCanonical = %s\n", g.urlCanonical); | |
| 127 | +} | |
| 93 | 128 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -31,20 +31,38 @@ | |
| 31 | ** |
| 32 | ** g.urlIsFile True if this is a file URL |
| 33 | ** g.urlName Hostname for HTTP:. Filename for FILE: |
| 34 | ** g.urlPort Port name for HTTP. |
| 35 | ** g.urlPath Path name for HTTP. |
| 36 | ** g.urlCanonical The URL in canonical form |
| 37 | ** |
| 38 | */ |
| 39 | void url_parse(const char *zUrl){ |
| 40 | int i, j, c; |
| 41 | char *zFile; |
| 42 | if( strncmp(zUrl, "http:", 5)==0 ){ |
| 43 | g.urlIsFile = 0; |
| 44 | for(i=7; (c=zUrl[i])!=0 && c!=':' && c!='/'; i++){} |
| 45 | g.urlName = mprintf("%.*s", i-7, &zUrl[7]); |
| 46 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 47 | if( c==':' ){ |
| 48 | g.urlPort = 0; |
| 49 | i++; |
| 50 | while( (c = zUrl[i])!=0 && isdigit(c) ){ |
| @@ -88,5 +106,22 @@ | |
| 88 | g.urlName = mprintf("%b", &cfile); |
| 89 | g.urlCanonical = mprintf("file://%T", g.urlName); |
| 90 | blob_reset(&cfile); |
| 91 | } |
| 92 | } |
| 93 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -31,20 +31,38 @@ | |
| 31 | ** |
| 32 | ** g.urlIsFile True if this is a file URL |
| 33 | ** g.urlName Hostname for HTTP:. Filename for FILE: |
| 34 | ** g.urlPort Port name for HTTP. |
| 35 | ** g.urlPath Path name for HTTP. |
| 36 | ** g.urlUser Userid. |
| 37 | ** g.urlPasswd Password. |
| 38 | ** g.urlCanonical The URL in canonical form |
| 39 | ** |
| 40 | ** HTTP url format is: |
| 41 | ** |
| 42 | ** http://userid:password@host:port/path?query#fragment |
| 43 | ** |
| 44 | */ |
| 45 | void url_parse(const char *zUrl){ |
| 46 | int i, j, c; |
| 47 | char *zFile = 0; |
| 48 | if( strncmp(zUrl, "http:", 5)==0 ){ |
| 49 | g.urlIsFile = 0; |
| 50 | for(i=7; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){} |
| 51 | if( c=='@' ){ |
| 52 | for(j=7; j<i && zUrl[j]!=':'; j++){} |
| 53 | g.urlUser = mprintf("%.*s", j-7, &zUrl[7]); |
| 54 | if( j<i ){ |
| 55 | g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]); |
| 56 | } |
| 57 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 58 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 59 | i = j; |
| 60 | }else{ |
| 61 | for(i=7; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 62 | g.urlName = mprintf("%.*s", i-7, &zUrl[7]); |
| 63 | } |
| 64 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 65 | if( c==':' ){ |
| 66 | g.urlPort = 0; |
| 67 | i++; |
| 68 | while( (c = zUrl[i])!=0 && isdigit(c) ){ |
| @@ -88,5 +106,22 @@ | |
| 106 | g.urlName = mprintf("%b", &cfile); |
| 107 | g.urlCanonical = mprintf("file://%T", g.urlName); |
| 108 | blob_reset(&cfile); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | /* |
| 113 | ** COMMAND: test-urlparser |
| 114 | */ |
| 115 | void cmd_test_urlparser(void){ |
| 116 | if( g.argc!=3 ){ |
| 117 | usage("URL"); |
| 118 | } |
| 119 | url_parse(g.argv[2]); |
| 120 | printf("g.urlIsFile = %d\n", g.urlIsFile); |
| 121 | printf("g.urlName = %s\n", g.urlName); |
| 122 | printf("g.urlPort = %d\n", g.urlPort); |
| 123 | printf("g.urlPath = %s\n", g.urlPath); |
| 124 | printf("g.urlUser = %s\n", g.urlUser); |
| 125 | printf("g.urlPasswd = %s\n", g.urlPasswd); |
| 126 | printf("g.urlCanonical = %s\n", g.urlCanonical); |
| 127 | } |
| 128 |
+9
-5
| --- src/user.c | ||
| +++ src/user.c | ||
| @@ -54,12 +54,12 @@ | ||
| 54 | 54 | char *z = getpass(zPrompt); |
| 55 | 55 | strip_string(pPassphrase, z); |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | 58 | /* |
| 59 | -** Prompt the user for a passphrase used to encrypt the private key | |
| 60 | -** portion of an RSA key pair. | |
| 59 | +** Prompt the user for a password. Store the result in the pPassphrase | |
| 60 | +** blob. | |
| 61 | 61 | ** |
| 62 | 62 | ** Behavior is controlled by the verify parameter: |
| 63 | 63 | ** |
| 64 | 64 | ** 0 Just ask once. |
| 65 | 65 | ** |
| @@ -66,11 +66,15 @@ | ||
| 66 | 66 | ** 1 If the first answer is a non-empty string, ask for |
| 67 | 67 | ** verification. Repeat if the two strings do not match. |
| 68 | 68 | ** |
| 69 | 69 | ** 2 Ask twice, repeat if the strings do not match. |
| 70 | 70 | */ |
| 71 | -static void get_passphrase(const char *zPrompt, Blob *pPassphrase, int verify){ | |
| 71 | +void prompt_for_password( | |
| 72 | + const char *zPrompt, | |
| 73 | + Blob *pPassphrase, | |
| 74 | + int verify | |
| 75 | +){ | |
| 72 | 76 | Blob secondTry; |
| 73 | 77 | blob_zero(pPassphrase); |
| 74 | 78 | blob_zero(&secondTry); |
| 75 | 79 | while(1){ |
| 76 | 80 | prompt_for_passphrase(zPrompt, pPassphrase); |
| @@ -117,11 +121,11 @@ | ||
| 117 | 121 | if( n>=2 && strncmp(g.argv[2],"new",n)==0 ){ |
| 118 | 122 | Blob passwd, login, contact; |
| 119 | 123 | |
| 120 | 124 | prompt_user("login: ", &login); |
| 121 | 125 | prompt_user("contact-info: ", &contact); |
| 122 | - get_passphrase("password: ", &passwd, 1); | |
| 126 | + prompt_for_password("password: ", &passwd, 1); | |
| 123 | 127 | db_multi_exec( |
| 124 | 128 | "INSERT INTO user(login,pw,cap,info)" |
| 125 | 129 | "VALUES(%B,%B,'jnor',%B)", |
| 126 | 130 | &login, &passwd, &contact |
| 127 | 131 | ); |
| @@ -149,11 +153,11 @@ | ||
| 149 | 153 | uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]); |
| 150 | 154 | if( uid==0 ){ |
| 151 | 155 | fossil_fatal("no such user: %s", g.argv[3]); |
| 152 | 156 | } |
| 153 | 157 | zPrompt = mprintf("new passwd for %s: ", g.argv[3]); |
| 154 | - get_passphrase(zPrompt, &pw, 1); | |
| 158 | + prompt_for_password(zPrompt, &pw, 1); | |
| 155 | 159 | if( blob_size(&pw)==0 ){ |
| 156 | 160 | printf("password unchanged\n"); |
| 157 | 161 | }else{ |
| 158 | 162 | db_multi_exec("UPDATE user SET pw=%B WHERE uid=%d", &pw, uid); |
| 159 | 163 | } |
| 160 | 164 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -54,12 +54,12 @@ | |
| 54 | char *z = getpass(zPrompt); |
| 55 | strip_string(pPassphrase, z); |
| 56 | } |
| 57 | |
| 58 | /* |
| 59 | ** Prompt the user for a passphrase used to encrypt the private key |
| 60 | ** portion of an RSA key pair. |
| 61 | ** |
| 62 | ** Behavior is controlled by the verify parameter: |
| 63 | ** |
| 64 | ** 0 Just ask once. |
| 65 | ** |
| @@ -66,11 +66,15 @@ | |
| 66 | ** 1 If the first answer is a non-empty string, ask for |
| 67 | ** verification. Repeat if the two strings do not match. |
| 68 | ** |
| 69 | ** 2 Ask twice, repeat if the strings do not match. |
| 70 | */ |
| 71 | static void get_passphrase(const char *zPrompt, Blob *pPassphrase, int verify){ |
| 72 | Blob secondTry; |
| 73 | blob_zero(pPassphrase); |
| 74 | blob_zero(&secondTry); |
| 75 | while(1){ |
| 76 | prompt_for_passphrase(zPrompt, pPassphrase); |
| @@ -117,11 +121,11 @@ | |
| 117 | if( n>=2 && strncmp(g.argv[2],"new",n)==0 ){ |
| 118 | Blob passwd, login, contact; |
| 119 | |
| 120 | prompt_user("login: ", &login); |
| 121 | prompt_user("contact-info: ", &contact); |
| 122 | get_passphrase("password: ", &passwd, 1); |
| 123 | db_multi_exec( |
| 124 | "INSERT INTO user(login,pw,cap,info)" |
| 125 | "VALUES(%B,%B,'jnor',%B)", |
| 126 | &login, &passwd, &contact |
| 127 | ); |
| @@ -149,11 +153,11 @@ | |
| 149 | uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]); |
| 150 | if( uid==0 ){ |
| 151 | fossil_fatal("no such user: %s", g.argv[3]); |
| 152 | } |
| 153 | zPrompt = mprintf("new passwd for %s: ", g.argv[3]); |
| 154 | get_passphrase(zPrompt, &pw, 1); |
| 155 | if( blob_size(&pw)==0 ){ |
| 156 | printf("password unchanged\n"); |
| 157 | }else{ |
| 158 | db_multi_exec("UPDATE user SET pw=%B WHERE uid=%d", &pw, uid); |
| 159 | } |
| 160 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -54,12 +54,12 @@ | |
| 54 | char *z = getpass(zPrompt); |
| 55 | strip_string(pPassphrase, z); |
| 56 | } |
| 57 | |
| 58 | /* |
| 59 | ** Prompt the user for a password. Store the result in the pPassphrase |
| 60 | ** blob. |
| 61 | ** |
| 62 | ** Behavior is controlled by the verify parameter: |
| 63 | ** |
| 64 | ** 0 Just ask once. |
| 65 | ** |
| @@ -66,11 +66,15 @@ | |
| 66 | ** 1 If the first answer is a non-empty string, ask for |
| 67 | ** verification. Repeat if the two strings do not match. |
| 68 | ** |
| 69 | ** 2 Ask twice, repeat if the strings do not match. |
| 70 | */ |
| 71 | void prompt_for_password( |
| 72 | const char *zPrompt, |
| 73 | Blob *pPassphrase, |
| 74 | int verify |
| 75 | ){ |
| 76 | Blob secondTry; |
| 77 | blob_zero(pPassphrase); |
| 78 | blob_zero(&secondTry); |
| 79 | while(1){ |
| 80 | prompt_for_passphrase(zPrompt, pPassphrase); |
| @@ -117,11 +121,11 @@ | |
| 121 | if( n>=2 && strncmp(g.argv[2],"new",n)==0 ){ |
| 122 | Blob passwd, login, contact; |
| 123 | |
| 124 | prompt_user("login: ", &login); |
| 125 | prompt_user("contact-info: ", &contact); |
| 126 | prompt_for_password("password: ", &passwd, 1); |
| 127 | db_multi_exec( |
| 128 | "INSERT INTO user(login,pw,cap,info)" |
| 129 | "VALUES(%B,%B,'jnor',%B)", |
| 130 | &login, &passwd, &contact |
| 131 | ); |
| @@ -149,11 +153,11 @@ | |
| 153 | uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]); |
| 154 | if( uid==0 ){ |
| 155 | fossil_fatal("no such user: %s", g.argv[3]); |
| 156 | } |
| 157 | zPrompt = mprintf("new passwd for %s: ", g.argv[3]); |
| 158 | prompt_for_password(zPrompt, &pw, 1); |
| 159 | if( blob_size(&pw)==0 ){ |
| 160 | printf("password unchanged\n"); |
| 161 | }else{ |
| 162 | db_multi_exec("UPDATE user SET pw=%B WHERE uid=%d", &pw, uid); |
| 163 | } |
| 164 |
+2
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -360,10 +360,11 @@ | ||
| 360 | 360 | cgi_reset_content(); |
| 361 | 361 | @ error wrong\sproject |
| 362 | 362 | nErr++; |
| 363 | 363 | break; |
| 364 | 364 | } |
| 365 | + login_check_credentials(); | |
| 365 | 366 | if( blob_eq(&aToken[0], "pull") ){ |
| 366 | 367 | if( !g.okRead ){ |
| 367 | 368 | cgi_reset_content(); |
| 368 | 369 | @ error not\sauthorized\sto\sread |
| 369 | 370 | nErr++; |
| @@ -385,10 +386,11 @@ | ||
| 385 | 386 | /* clone |
| 386 | 387 | ** |
| 387 | 388 | ** The client knows nothing. Tell all. |
| 388 | 389 | */ |
| 389 | 390 | if( blob_eq(&aToken[0], "clone") ){ |
| 391 | + login_check_credentials(); | |
| 390 | 392 | if( !g.okRead ){ |
| 391 | 393 | cgi_reset_content(); |
| 392 | 394 | @ error not\sauthorized\sto\sread |
| 393 | 395 | nErr++; |
| 394 | 396 | break; |
| 395 | 397 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -360,10 +360,11 @@ | |
| 360 | cgi_reset_content(); |
| 361 | @ error wrong\sproject |
| 362 | nErr++; |
| 363 | break; |
| 364 | } |
| 365 | if( blob_eq(&aToken[0], "pull") ){ |
| 366 | if( !g.okRead ){ |
| 367 | cgi_reset_content(); |
| 368 | @ error not\sauthorized\sto\sread |
| 369 | nErr++; |
| @@ -385,10 +386,11 @@ | |
| 385 | /* clone |
| 386 | ** |
| 387 | ** The client knows nothing. Tell all. |
| 388 | */ |
| 389 | if( blob_eq(&aToken[0], "clone") ){ |
| 390 | if( !g.okRead ){ |
| 391 | cgi_reset_content(); |
| 392 | @ error not\sauthorized\sto\sread |
| 393 | nErr++; |
| 394 | break; |
| 395 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -360,10 +360,11 @@ | |
| 360 | cgi_reset_content(); |
| 361 | @ error wrong\sproject |
| 362 | nErr++; |
| 363 | break; |
| 364 | } |
| 365 | login_check_credentials(); |
| 366 | if( blob_eq(&aToken[0], "pull") ){ |
| 367 | if( !g.okRead ){ |
| 368 | cgi_reset_content(); |
| 369 | @ error not\sauthorized\sto\sread |
| 370 | nErr++; |
| @@ -385,10 +386,11 @@ | |
| 386 | /* clone |
| 387 | ** |
| 388 | ** The client knows nothing. Tell all. |
| 389 | */ |
| 390 | if( blob_eq(&aToken[0], "clone") ){ |
| 391 | login_check_credentials(); |
| 392 | if( !g.okRead ){ |
| 393 | cgi_reset_content(); |
| 394 | @ error not\sauthorized\sto\sread |
| 395 | nErr++; |
| 396 | break; |
| 397 |