Fossil

Check-in [0110b93e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:If a sync login fails, prompt for a new password and repeat the attempt.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 0110b93e0c821c5c07050866bf354e559e69e8b2
User & Date: drh 2010-01-21 20:14:07
Context
2010-01-21
20:28
Cleanup the last-sync-url password handling. Automatically prompt for a new password if a sync login card fails. check-in: 05380c5f user: drh tags: experimental
20:14
If a sync login fails, prompt for a new password and repeat the attempt. check-in: 0110b93e user: drh tags: experimental
19:51
Better reporting of failed logins by the server back to the client. check-in: b030521c user: drh tags: experimental
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/xfer.c.

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
...
376
377
378
379
380
381
382


383
384
385
386
387
388
389
390
391
...
437
438
439
440
441
442
443
444
445
446
447

448
449
450
451
452
453
454
...
742
743
744
745
746
747
748

749
750






751
752
753
754
755
756
757
....
1068
1069
1070
1071
1072
1073
1074

1075
1076
1077
1078
1079
1080
1081
....
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
....
1243
1244
1245
1246
1247
1248
1249





1250

1251
1252
1253
1254
1255
1256
1257
1258
....
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
    pXfer->nGimmeSent++;
  }
  db_finalize(&q);
}

/*
** Compute an SHA1 hash on the tail of pMsg.  Verify that it matches the
** the hash given in pHash.  Return 1 on a successful match.  Return 0
** if there is a mismatch.
*/
static int check_tail_hash(Blob *pHash, Blob *pMsg){
  Blob tail;
  Blob h2;
  int rc;
  blob_tail(pMsg, &tail);
  sha1sum_blob(&tail, &h2);
  rc = blob_compare(pHash, &h2);
  blob_reset(&h2);
  blob_reset(&tail);
  return rc==0;
}

/*
** Check the signature on an application/x-fossil payload received by
** the HTTP server.  The signature is a line of the following form:
**
**        login LOGIN NONCE SIGNATURE
................................................................................
** If everything checks out, the USER.CAP column for the USER table
** is consulted to set privileges in the global g variable.
**
** If anything fails to check out, no changes are made to privileges.
**
** Signature generation on the client side is handled by the 
** http_exchange() routine.


*/
void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
  Stmt q;
  int rc = -1;
  char *zLogin = blob_terminate(pLogin);
  defossilize(zLogin);

  db_prepare(&q,
     "SELECT pw, cap, uid FROM user"
................................................................................
    }
  }
  db_finalize(&q);

  if( rc==0 ){
    /* If the login was successful. */
    login_set_anon_nobody_capabilities();
  }else{
    /* Login failed */
    @ message login\sfailed
  }

}

/*
** Send the content of all files in the unsent table.
**
** This is really just an optimization.  If you clear the
** unsent table, all the right files will still get transferred.
................................................................................
    ** The client can send multiple logins.  Permissions are cumulative.
    */
    if( blob_eq(&xfer.aToken[0], "login")
     && xfer.nToken==4
    ){
      if( disableLogin ){
        g.okRead = g.okWrite = 1;

      }else if( check_tail_hash(&xfer.aToken[2], xfer.pIn) ){
        check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]);






      }
    }else
    
    /*    reqconfig  NAME
    **
    ** Request a configuration value
    */
................................................................................
      blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    if( pushFlag ){
      blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
      nCardSent++;
    }


    /* Process the reply that came back from the server */
    while( blob_line(&recv, &xfer.line) ){
      if( blob_buffer(&xfer.line)[0]=='#' ){
        continue;
      }
      xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
................................................................................
      **
      ** If the "login failed" message is seen, clear the sync password prior
      ** to the next cycle.
      */        
      if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
        char *zMsg = blob_terminate(&xfer.aToken[1]);
        defossilize(zMsg);
        if( strcmp(zMsg, "login failed")==0 ){
          if( cloneFlag && nCycle==0 ){
            zMsg = 0;
          }else{
            if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
            g.urlPasswd = 0;
          }
        }
        if( zMsg ) printf("\rServer says: %s\n", zMsg);
      }else

      /*   error MESSAGE
      **
      ** Report an error and abandon the sync session.
      **
................................................................................
      ** subsequent messages should be OK.  Nevertheless, we need to ignore
      ** the error card on the first message of a clone.
      */        
      if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
        if( !cloneFlag || nCycle>0 ){
          char *zMsg = blob_terminate(&xfer.aToken[1]);
          defossilize(zMsg);





          blob_appendf(&xfer.err, "server says: %s", zMsg);

          printf("Server Error: %s\n", zMsg);
        }
      }else

      /* Unknown message */
      {
        if( blob_str(&xfer.aToken[0])[0]=='<' ){
          fossil_fatal(
................................................................................
    if( nCardRcvd>0 ){
      printf(zValueFormat, "Received:",
              blob_size(&recv), nCardRcvd,
              xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
    }
    blob_reset(&recv);
    nCycle++;
    go = 0;

    /* If we received one or more files on the previous exchange but
    ** there are still phantoms, then go another round.
    */
    nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
    if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
      go = 1;







|
<










|







 







>
>

|







 







<
<
<

>







 







>
|
|
>
>
>
>
>
>







 







>







 







<
<
<
<
<
<
<
<







 







>
>
>
>
>
|
>
|







 







<







340
341
342
343
344
345
346
347

348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
...
438
439
440
441
442
443
444



445
446
447
448
449
450
451
452
453
...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
....
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
....
1224
1225
1226
1227
1228
1229
1230








1231
1232
1233
1234
1235
1236
1237
....
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
....
1281
1282
1283
1284
1285
1286
1287

1288
1289
1290
1291
1292
1293
1294
    pXfer->nGimmeSent++;
  }
  db_finalize(&q);
}

/*
** Compute an SHA1 hash on the tail of pMsg.  Verify that it matches the
** the hash given in pHash.  Return non-zero for an error and 0 on success.

*/
static int check_tail_hash(Blob *pHash, Blob *pMsg){
  Blob tail;
  Blob h2;
  int rc;
  blob_tail(pMsg, &tail);
  sha1sum_blob(&tail, &h2);
  rc = blob_compare(pHash, &h2);
  blob_reset(&h2);
  blob_reset(&tail);
  return rc;
}

/*
** Check the signature on an application/x-fossil payload received by
** the HTTP server.  The signature is a line of the following form:
**
**        login LOGIN NONCE SIGNATURE
................................................................................
** If everything checks out, the USER.CAP column for the USER table
** is consulted to set privileges in the global g variable.
**
** If anything fails to check out, no changes are made to privileges.
**
** Signature generation on the client side is handled by the 
** http_exchange() routine.
**
** Return non-zero for a login failure and zero for success.
*/
int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
  Stmt q;
  int rc = -1;
  char *zLogin = blob_terminate(pLogin);
  defossilize(zLogin);

  db_prepare(&q,
     "SELECT pw, cap, uid FROM user"
................................................................................
    }
  }
  db_finalize(&q);

  if( rc==0 ){
    /* If the login was successful. */
    login_set_anon_nobody_capabilities();



  }
  return rc;
}

/*
** Send the content of all files in the unsent table.
**
** This is really just an optimization.  If you clear the
** unsent table, all the right files will still get transferred.
................................................................................
    ** The client can send multiple logins.  Permissions are cumulative.
    */
    if( blob_eq(&xfer.aToken[0], "login")
     && xfer.nToken==4
    ){
      if( disableLogin ){
        g.okRead = g.okWrite = 1;
      }else{
        if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
         || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
        ){
          cgi_reset_content();
          @ error login\sfailed
          nErr++;
          break;
        }        
      }
    }else
    
    /*    reqconfig  NAME
    **
    ** Request a configuration value
    */
................................................................................
      blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    if( pushFlag ){
      blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    go = 0;

    /* Process the reply that came back from the server */
    while( blob_line(&recv, &xfer.line) ){
      if( blob_buffer(&xfer.line)[0]=='#' ){
        continue;
      }
      xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
................................................................................
      **
      ** If the "login failed" message is seen, clear the sync password prior
      ** to the next cycle.
      */        
      if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
        char *zMsg = blob_terminate(&xfer.aToken[1]);
        defossilize(zMsg);








        if( zMsg ) printf("\rServer says: %s\n", zMsg);
      }else

      /*   error MESSAGE
      **
      ** Report an error and abandon the sync session.
      **
................................................................................
      ** subsequent messages should be OK.  Nevertheless, we need to ignore
      ** the error card on the first message of a clone.
      */        
      if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
        if( !cloneFlag || nCycle>0 ){
          char *zMsg = blob_terminate(&xfer.aToken[1]);
          defossilize(zMsg);
          if( strcmp(zMsg, "login failed")==0 ){
            if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
            g.urlPasswd = 0;
            if( nCycle<2 ) go = 1;
          }else{
            blob_appendf(&xfer.err, "\rserver says: %s", zMsg);
          }
          printf("\rServer Error: %s\n", zMsg);
        }
      }else

      /* Unknown message */
      {
        if( blob_str(&xfer.aToken[0])[0]=='<' ){
          fossil_fatal(
................................................................................
    if( nCardRcvd>0 ){
      printf(zValueFormat, "Received:",
              blob_size(&recv), nCardRcvd,
              xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
    }
    blob_reset(&recv);
    nCycle++;


    /* If we received one or more files on the previous exchange but
    ** there are still phantoms, then go another round.
    */
    nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
    if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
      go = 1;