Fossil SCM

For testing purposes only, unconditionally use the X-Fossil-Xfer-Login HTTP header for sync requests, rather than add it to the payload (which seems to work okay). This is primarily so that apples-to-apples comparisons can be made in libfossil's testing, and will be reverted (or applied conditionally) once the libfossil side is working.

stephan 2025-07-22 02:16 xfer-login-card
Commit ff942066d5bb2ce61ee7981895f3b6e0bb4e212ab6eff532e28d18ce34819a2e
4 files changed +1 -1 +25 -2 +1 -1 +32 -8
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.27
1
+2.27.1
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.27
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.27.1
2
+25 -2
--- src/http.c
+++ src/http.c
@@ -119,11 +119,11 @@
119119
g.url.passwd = fossil_strdup(zPw);
120120
}
121121
122122
blob_append(&pw, zPw, -1);
123123
sha1sum_blob(&pw, &sig);
124
- blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig);
124
+ blob_appendf(pLogin, "login %F %b %b", zLogin, &nonce, &sig);
125125
blob_reset(&pw);
126126
blob_reset(&sig);
127127
blob_reset(&nonce);
128128
}
129129
@@ -131,10 +131,11 @@
131131
** Construct an appropriate HTTP request header. Write the header
132132
** into pHdr. This routine initializes the pHdr blob. pPayload is
133133
** the complete payload (including the login card) already compressed.
134134
*/
135135
static void http_build_header(
136
+ Blob *pLogin, /* Login card or NULL */
136137
Blob *pPayload, /* the payload that will be sent */
137138
Blob *pHdr, /* construct the header here */
138139
const char *zAltMimetype /* Alternative mimetype */
139140
){
140141
int nPayload = pPayload ? blob_size(pPayload) : 0;
@@ -153,10 +154,13 @@
153154
fossil_free(zEncoded);
154155
}
155156
blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
156157
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
157158
if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
159
+ if( pLogin ){
160
+ blob_appendf(pHdr, "X-Fossil-Xfer-Login: %b\r\n", pLogin);
161
+ }
158162
if( nPayload ){
159163
if( zAltMimetype ){
160164
blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
161165
}else if( g.fHttpTrace ){
162166
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
@@ -460,25 +464,44 @@
460464
return 1;
461465
}
462466
463467
/* Construct the login card and prepare the complete payload */
464468
if( blob_size(pSend)==0 ){
469
+ blob_zero(&login);
465470
blob_zero(&payload);
466471
}else{
467472
blob_zero(&login);
468473
if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
474
+#if RELEASE_VERSION_NUMBER >= 22701
475
+ if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
476
+ /*blob_append(&payload, blob_buffer(pSend), blob_size(pSend));*/
477
+ blob_zero(&payload);
478
+ blob_swap(pSend, &payload);
479
+ }else{
480
+ blob_compress(pSend, &payload);
481
+ }
482
+#else
469483
if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
484
+ if( blob_size(&login) ){
485
+ blob_append_char(&login, '\n');
486
+ }
470487
payload = login;
471488
blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
472489
}else{
490
+ if( blob_size(&login) ){
491
+ blob_append_char(&login, '\n');
492
+ }
473493
blob_compress2(&login, pSend, &payload);
474494
blob_reset(&login);
475495
}
496
+#endif
476497
}
477498
478499
/* Construct the HTTP request header */
479
- http_build_header(&payload, &hdr, zAltMimetype);
500
+ http_build_header(blob_size(&login) ? &login : 0,
501
+ &payload, &hdr, zAltMimetype);
502
+ blob_reset(&login);
480503
481504
/* When tracing, write the transmitted HTTP message both to standard
482505
** output and into a file. The file can then be used to drive the
483506
** server-side like this:
484507
**
485508
--- src/http.c
+++ src/http.c
@@ -119,11 +119,11 @@
119 g.url.passwd = fossil_strdup(zPw);
120 }
121
122 blob_append(&pw, zPw, -1);
123 sha1sum_blob(&pw, &sig);
124 blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig);
125 blob_reset(&pw);
126 blob_reset(&sig);
127 blob_reset(&nonce);
128 }
129
@@ -131,10 +131,11 @@
131 ** Construct an appropriate HTTP request header. Write the header
132 ** into pHdr. This routine initializes the pHdr blob. pPayload is
133 ** the complete payload (including the login card) already compressed.
134 */
135 static void http_build_header(
 
136 Blob *pPayload, /* the payload that will be sent */
137 Blob *pHdr, /* construct the header here */
138 const char *zAltMimetype /* Alternative mimetype */
139 ){
140 int nPayload = pPayload ? blob_size(pPayload) : 0;
@@ -153,10 +154,13 @@
153 fossil_free(zEncoded);
154 }
155 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
156 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
157 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
 
 
 
158 if( nPayload ){
159 if( zAltMimetype ){
160 blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
161 }else if( g.fHttpTrace ){
162 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
@@ -460,25 +464,44 @@
460 return 1;
461 }
462
463 /* Construct the login card and prepare the complete payload */
464 if( blob_size(pSend)==0 ){
 
465 blob_zero(&payload);
466 }else{
467 blob_zero(&login);
468 if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
 
 
 
 
 
 
 
 
 
469 if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
 
 
 
470 payload = login;
471 blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
472 }else{
 
 
 
473 blob_compress2(&login, pSend, &payload);
474 blob_reset(&login);
475 }
 
476 }
477
478 /* Construct the HTTP request header */
479 http_build_header(&payload, &hdr, zAltMimetype);
 
 
480
481 /* When tracing, write the transmitted HTTP message both to standard
482 ** output and into a file. The file can then be used to drive the
483 ** server-side like this:
484 **
485
--- src/http.c
+++ src/http.c
@@ -119,11 +119,11 @@
119 g.url.passwd = fossil_strdup(zPw);
120 }
121
122 blob_append(&pw, zPw, -1);
123 sha1sum_blob(&pw, &sig);
124 blob_appendf(pLogin, "login %F %b %b", zLogin, &nonce, &sig);
125 blob_reset(&pw);
126 blob_reset(&sig);
127 blob_reset(&nonce);
128 }
129
@@ -131,10 +131,11 @@
131 ** Construct an appropriate HTTP request header. Write the header
132 ** into pHdr. This routine initializes the pHdr blob. pPayload is
133 ** the complete payload (including the login card) already compressed.
134 */
135 static void http_build_header(
136 Blob *pLogin, /* Login card or NULL */
137 Blob *pPayload, /* the payload that will be sent */
138 Blob *pHdr, /* construct the header here */
139 const char *zAltMimetype /* Alternative mimetype */
140 ){
141 int nPayload = pPayload ? blob_size(pPayload) : 0;
@@ -153,10 +154,13 @@
154 fossil_free(zEncoded);
155 }
156 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
157 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
158 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
159 if( pLogin ){
160 blob_appendf(pHdr, "X-Fossil-Xfer-Login: %b\r\n", pLogin);
161 }
162 if( nPayload ){
163 if( zAltMimetype ){
164 blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
165 }else if( g.fHttpTrace ){
166 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
@@ -460,25 +464,44 @@
464 return 1;
465 }
466
467 /* Construct the login card and prepare the complete payload */
468 if( blob_size(pSend)==0 ){
469 blob_zero(&login);
470 blob_zero(&payload);
471 }else{
472 blob_zero(&login);
473 if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
474 #if RELEASE_VERSION_NUMBER >= 22701
475 if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
476 /*blob_append(&payload, blob_buffer(pSend), blob_size(pSend));*/
477 blob_zero(&payload);
478 blob_swap(pSend, &payload);
479 }else{
480 blob_compress(pSend, &payload);
481 }
482 #else
483 if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
484 if( blob_size(&login) ){
485 blob_append_char(&login, '\n');
486 }
487 payload = login;
488 blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
489 }else{
490 if( blob_size(&login) ){
491 blob_append_char(&login, '\n');
492 }
493 blob_compress2(&login, pSend, &payload);
494 blob_reset(&login);
495 }
496 #endif
497 }
498
499 /* Construct the HTTP request header */
500 http_build_header(blob_size(&login) ? &login : 0,
501 &payload, &hdr, zAltMimetype);
502 blob_reset(&login);
503
504 /* When tracing, write the transmitted HTTP message both to standard
505 ** output and into a file. The file can then be used to drive the
506 ** server-side like this:
507 **
508
+1 -1
--- src/user.c
+++ src/user.c
@@ -465,11 +465,11 @@
465465
char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0);
466466
db_unprotect(PROTECT_USER);
467467
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
468468
zSecret, uid);
469469
db_protect_pop();
470
- free(zSecret);
470
+ fossil_free(zSecret);
471471
}
472472
}else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
473473
int uid;
474474
if( g.argc!=4 && g.argc!=5 ){
475475
usage("capabilities USERNAME ?PERMISSIONS?");
476476
--- src/user.c
+++ src/user.c
@@ -465,11 +465,11 @@
465 char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0);
466 db_unprotect(PROTECT_USER);
467 db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
468 zSecret, uid);
469 db_protect_pop();
470 free(zSecret);
471 }
472 }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
473 int uid;
474 if( g.argc!=4 && g.argc!=5 ){
475 usage("capabilities USERNAME ?PERMISSIONS?");
476
--- src/user.c
+++ src/user.c
@@ -465,11 +465,11 @@
465 char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0);
466 db_unprotect(PROTECT_USER);
467 db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
468 zSecret, uid);
469 db_protect_pop();
470 fossil_free(zSecret);
471 }
472 }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
473 int uid;
474 if( g.argc!=4 && g.argc!=5 ){
475 usage("capabilities USERNAME ?PERMISSIONS?");
476
+32 -8
--- src/xfer.c
+++ src/xfer.c
@@ -790,10 +790,15 @@
790790
static int check_tail_hash(Blob *pHash, Blob *pMsg){
791791
Blob tail;
792792
int rc;
793793
blob_tail(pMsg, &tail);
794794
rc = hname_verify_hash(&tail, blob_buffer(pHash), blob_size(pHash));
795
+#if 0
796
+ fprintf(stderr, "check tail=%d hash=[%.*s]\ntail=<<%.*s>>\n", rc,
797
+ blob_size(pHash), blob_str(pHash),
798
+ blob_size(&tail), blob_str(&tail));
799
+#endif
795800
blob_reset(&tail);
796801
return rc==HNAME_ERROR;
797802
}
798803
799804
/*
@@ -827,11 +832,11 @@
827832
int rc = -1;
828833
char *zLogin = blob_terminate(pLogin);
829834
defossilize(zLogin);
830835
831836
if( fossil_strcmp(zLogin, "nobody")==0
832
- || fossil_strcmp(zLogin,"anonymous")==0
837
+ || fossil_strcmp(zLogin, "anonymous")==0
833838
){
834839
return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
835840
}
836841
if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
837842
&& db_get_boolean("remote_user_ok",0) ){
@@ -854,10 +859,19 @@
854859
blob_copy(&combined, pNonce);
855860
blob_append(&combined, blob_buffer(&pw), szPw);
856861
sha1sum_blob(&combined, &hash);
857862
assert( blob_size(&hash)==40 );
858863
rc = blob_constant_time_cmp(&hash, pSig);
864
+#if 0
865
+ fprintf(stderr,
866
+ "check login rc=%d nonce=[%.*s] pSig=[%.*s] .hash=[%.*s]\n",
867
+ rc,
868
+ blob_size(pNonce), blob_str(pNonce),
869
+ blob_size(pSig), blob_str(pSig),
870
+ blob_size(&hash), blob_str(&hash));
871
+
872
+#endif
859873
blob_reset(&hash);
860874
blob_reset(&combined);
861875
if( rc!=0 && szPw!=40 ){
862876
/* If this server stores cleartext passwords and the password did not
863877
** match, then perhaps the client is sending SHA1 passwords. Try
@@ -1318,21 +1332,26 @@
13181332
pzUuidList = &zUuidList;
13191333
pnUuidList = &nUuidList;
13201334
}
13211335
if( g.zLoginCard ){
13221336
/* Login card received via HTTP header X-Fossil-Xfer-Login */
1323
- blob_init(&xfer.line, g.zLoginCard, -1);
1337
+ blob_zero(&xfer.line);
1338
+ blob_append(&xfer.line, g.zLoginCard, -1);
13241339
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken,
13251340
count(xfer.aToken));
1326
- if( xfer.nToken==4
1327
- && blob_eq(&xfer.aToken[0], "login") ){
1328
- /*fprintf(stderr,"g.zLoginCard=%s nToken=%d\n", g.zLoginCard,
1329
- xfer.nToken);*/
1330
- goto handle_login_card;
1331
- }
1341
+#if 0
1342
+ fprintf(stderr,"%s:%d: g.zLoginCard=[%s]\nnToken=%d tok[0]=%s line=%s\n",
1343
+ __FILE__, __LINE__, g.zLoginCard,
1344
+ xfer.nToken, xfer.nToken ? blob_str(&xfer.aToken[0]) : "<NULL>",
1345
+ blob_str(&xfer.line));
1346
+#endif
13321347
fossil_free( g.zLoginCard );
13331348
g.zLoginCard = 0;
1349
+ if( xfer.nToken==4
1350
+ && blob_eq(&xfer.aToken[0], "login") ){
1351
+ goto handle_login_card;
1352
+ }
13341353
}
13351354
while( blob_line(xfer.pIn, &xfer.line) ){
13361355
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
13371356
if( blob_size(&xfer.line)==0 ) continue;
13381357
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
@@ -1584,10 +1603,15 @@
15841603
cgi_reset_content();
15851604
@ error multiple\slogin\cards
15861605
nErr++;
15871606
break;
15881607
}else{
1608
+#if 0
1609
+ fprintf(stderr, "handle_login_card: aToken[2]=[%.*s]\n",
1610
+ blob_size(&xfer.aToken[2]),
1611
+ blob_str(&xfer.aToken[2]));
1612
+#endif
15891613
if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
15901614
|| check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
15911615
){
15921616
cgi_reset_content();
15931617
@ error login\sfailed
15941618
--- src/xfer.c
+++ src/xfer.c
@@ -790,10 +790,15 @@
790 static int check_tail_hash(Blob *pHash, Blob *pMsg){
791 Blob tail;
792 int rc;
793 blob_tail(pMsg, &tail);
794 rc = hname_verify_hash(&tail, blob_buffer(pHash), blob_size(pHash));
 
 
 
 
 
795 blob_reset(&tail);
796 return rc==HNAME_ERROR;
797 }
798
799 /*
@@ -827,11 +832,11 @@
827 int rc = -1;
828 char *zLogin = blob_terminate(pLogin);
829 defossilize(zLogin);
830
831 if( fossil_strcmp(zLogin, "nobody")==0
832 || fossil_strcmp(zLogin,"anonymous")==0
833 ){
834 return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
835 }
836 if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
837 && db_get_boolean("remote_user_ok",0) ){
@@ -854,10 +859,19 @@
854 blob_copy(&combined, pNonce);
855 blob_append(&combined, blob_buffer(&pw), szPw);
856 sha1sum_blob(&combined, &hash);
857 assert( blob_size(&hash)==40 );
858 rc = blob_constant_time_cmp(&hash, pSig);
 
 
 
 
 
 
 
 
 
859 blob_reset(&hash);
860 blob_reset(&combined);
861 if( rc!=0 && szPw!=40 ){
862 /* If this server stores cleartext passwords and the password did not
863 ** match, then perhaps the client is sending SHA1 passwords. Try
@@ -1318,21 +1332,26 @@
1318 pzUuidList = &zUuidList;
1319 pnUuidList = &nUuidList;
1320 }
1321 if( g.zLoginCard ){
1322 /* Login card received via HTTP header X-Fossil-Xfer-Login */
1323 blob_init(&xfer.line, g.zLoginCard, -1);
 
1324 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken,
1325 count(xfer.aToken));
1326 if( xfer.nToken==4
1327 && blob_eq(&xfer.aToken[0], "login") ){
1328 /*fprintf(stderr,"g.zLoginCard=%s nToken=%d\n", g.zLoginCard,
1329 xfer.nToken);*/
1330 goto handle_login_card;
1331 }
1332 fossil_free( g.zLoginCard );
1333 g.zLoginCard = 0;
 
 
 
 
1334 }
1335 while( blob_line(xfer.pIn, &xfer.line) ){
1336 if( blob_buffer(&xfer.line)[0]=='#' ) continue;
1337 if( blob_size(&xfer.line)==0 ) continue;
1338 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
@@ -1584,10 +1603,15 @@
1584 cgi_reset_content();
1585 @ error multiple\slogin\cards
1586 nErr++;
1587 break;
1588 }else{
 
 
 
 
 
1589 if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
1590 || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
1591 ){
1592 cgi_reset_content();
1593 @ error login\sfailed
1594
--- src/xfer.c
+++ src/xfer.c
@@ -790,10 +790,15 @@
790 static int check_tail_hash(Blob *pHash, Blob *pMsg){
791 Blob tail;
792 int rc;
793 blob_tail(pMsg, &tail);
794 rc = hname_verify_hash(&tail, blob_buffer(pHash), blob_size(pHash));
795 #if 0
796 fprintf(stderr, "check tail=%d hash=[%.*s]\ntail=<<%.*s>>\n", rc,
797 blob_size(pHash), blob_str(pHash),
798 blob_size(&tail), blob_str(&tail));
799 #endif
800 blob_reset(&tail);
801 return rc==HNAME_ERROR;
802 }
803
804 /*
@@ -827,11 +832,11 @@
832 int rc = -1;
833 char *zLogin = blob_terminate(pLogin);
834 defossilize(zLogin);
835
836 if( fossil_strcmp(zLogin, "nobody")==0
837 || fossil_strcmp(zLogin, "anonymous")==0
838 ){
839 return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
840 }
841 if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
842 && db_get_boolean("remote_user_ok",0) ){
@@ -854,10 +859,19 @@
859 blob_copy(&combined, pNonce);
860 blob_append(&combined, blob_buffer(&pw), szPw);
861 sha1sum_blob(&combined, &hash);
862 assert( blob_size(&hash)==40 );
863 rc = blob_constant_time_cmp(&hash, pSig);
864 #if 0
865 fprintf(stderr,
866 "check login rc=%d nonce=[%.*s] pSig=[%.*s] .hash=[%.*s]\n",
867 rc,
868 blob_size(pNonce), blob_str(pNonce),
869 blob_size(pSig), blob_str(pSig),
870 blob_size(&hash), blob_str(&hash));
871
872 #endif
873 blob_reset(&hash);
874 blob_reset(&combined);
875 if( rc!=0 && szPw!=40 ){
876 /* If this server stores cleartext passwords and the password did not
877 ** match, then perhaps the client is sending SHA1 passwords. Try
@@ -1318,21 +1332,26 @@
1332 pzUuidList = &zUuidList;
1333 pnUuidList = &nUuidList;
1334 }
1335 if( g.zLoginCard ){
1336 /* Login card received via HTTP header X-Fossil-Xfer-Login */
1337 blob_zero(&xfer.line);
1338 blob_append(&xfer.line, g.zLoginCard, -1);
1339 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken,
1340 count(xfer.aToken));
1341 #if 0
1342 fprintf(stderr,"%s:%d: g.zLoginCard=[%s]\nnToken=%d tok[0]=%s line=%s\n",
1343 __FILE__, __LINE__, g.zLoginCard,
1344 xfer.nToken, xfer.nToken ? blob_str(&xfer.aToken[0]) : "<NULL>",
1345 blob_str(&xfer.line));
1346 #endif
1347 fossil_free( g.zLoginCard );
1348 g.zLoginCard = 0;
1349 if( xfer.nToken==4
1350 && blob_eq(&xfer.aToken[0], "login") ){
1351 goto handle_login_card;
1352 }
1353 }
1354 while( blob_line(xfer.pIn, &xfer.line) ){
1355 if( blob_buffer(&xfer.line)[0]=='#' ) continue;
1356 if( blob_size(&xfer.line)==0 ) continue;
1357 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
@@ -1584,10 +1603,15 @@
1603 cgi_reset_content();
1604 @ error multiple\slogin\cards
1605 nErr++;
1606 break;
1607 }else{
1608 #if 0
1609 fprintf(stderr, "handle_login_card: aToken[2]=[%.*s]\n",
1610 blob_size(&xfer.aToken[2]),
1611 blob_str(&xfer.aToken[2]));
1612 #endif
1613 if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
1614 || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
1615 ){
1616 cgi_reset_content();
1617 @ error login\sfailed
1618

Keyboard Shortcuts

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