Browse Source

ckdb/php - allow cancelling 2fa setup and removing 2fa directly

master
kanoi 9 years ago
parent
commit
3c6b81fd67
  1. 42
      pool/email.php
  2. 77
      pool/page_2fa.php
  3. 5
      src/ckdb.h
  4. 21
      src/ckdb_cmd.c
  5. 9
      src/ckdb_crypt.c

42
pool/email.php

@ -186,7 +186,7 @@ function twofaSetup($to, $whoip, $emailinfo)
return false; return false;
$message = "2FA is ready to be tested.$eol"; $message = "2FA is ready to be tested.$eol";
$message = "It will be enabled once you test it.$eol$eol"; $message .= "It will be enabled once you test it.$eol$eol";
$message .= $ret; $message .= $ret;
return sendnoheader($to, "2FA is Ready to be Enabled", $message, $emailinfo); return sendnoheader($to, "2FA is Ready to be Enabled", $message, $emailinfo);
@ -211,6 +211,46 @@ function twofaEnabled($to, $whoip, $emailinfo)
return sendnoheader($to, "2FA is Enabled", $message, $emailinfo); return sendnoheader($to, "2FA is Enabled", $message, $emailinfo);
} }
# #
function twofaCancel($to, $whoip, $emailinfo)
{
global $eol;
if (!isset($emailinfo['KWebURL']))
return false;
$web = $emailinfo['KWebURL'];
$ret = emailEnd('2fa change', $whoip, $emailinfo);
if ($ret === false)
return false;
$message = "2FA setup was cancelled on your account.$eol";
$message .= "You can set it up later if you want.$eol$eol";
$message .= $ret;
return sendnoheader($to, "2FA was Cancelled", $message, $emailinfo);
}
#
function twofaRemove($to, $whoip, $emailinfo)
{
global $eol;
if (!isset($emailinfo['KWebURL']))
return false;
$web = $emailinfo['KWebURL'];
$ret = emailEnd('2fa change', $whoip, $emailinfo);
if ($ret === false)
return false;
$message = "2FA was removed from your account.$eol";
$message .= "You can set it up again later if you want.$eol$eol";
$message .= $ret;
return sendnoheader($to, "2FA was Removed", $message, $emailinfo);
}
#
# getOpts required for email # getOpts required for email
# If they aren't all setup in the DB then email functions will return false # If they aren't all setup in the DB then email functions will return false
function emailOptList() function emailOptList()

77
pool/page_2fa.php

@ -23,7 +23,6 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$pg .= '<table cellpadding=20 cellspacing=0 border=1>'; $pg .= '<table cellpadding=20 cellspacing=0 border=1>';
$pg .= '<tr class=dc><td><center>'; $pg .= '<tr class=dc><td><center>';
$pg .= makeForm('2fa');
$pg .= '<table cellpadding=5 cellspacing=0 border=0>'; $pg .= '<table cellpadding=5 cellspacing=0 border=0>';
$pg .= '<tr class=dc><td>'; $pg .= '<tr class=dc><td>';
switch ($tfa) switch ($tfa)
@ -33,9 +32,10 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$pg .= "You don't have Two Factor Authentication (2FA) setup yet<br><br>"; $pg .= "You don't have Two Factor Authentication (2FA) setup yet<br><br>";
$pg .= 'To use 2FA you need an App on your phone/tablet<br>'; $pg .= 'To use 2FA you need an App on your phone/tablet<br>';
$pg .= app_txt('ones'); $pg .= app_txt('ones');
$pg .= makeForm('2fa');
$pg .= 'Click here to begin the setup process for 2FA: '; $pg .= 'Click here to begin the setup process for 2FA: ';
$pg .= '<input type=submit name=Setup value=Setup>'; $pg .= '<input type=submit name=Setup value=Setup>';
$pg .= '</td></tr>'; $pg .= '</form></td></tr>';
break; break;
case 'test': case 'test':
$pg .= '<tr class=dc><td>'; $pg .= '<tr class=dc><td>';
@ -66,8 +66,9 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$pg .= '<div id=can0><canvas id=can width=1 height=1>'; $pg .= '<div id=can0><canvas id=can width=1 height=1>';
$pg .= 'A qrcode will show here if your browser supports html5/canvas'; $pg .= 'A qrcode will show here if your browser supports html5/canvas';
$pg .= "</canvas></div><br>"; $pg .= "</canvas></div><br>";
$pg .= makeForm('2fa');
$pg .= 'Then enter your App 2FA Value: <input name=Value value="" size=10> '; $pg .= 'Then enter your App 2FA Value: <input name=Value value="" size=10> ';
$pg .= '<input type=submit name=Test value=Test></td></tr>'; $pg .= '<input type=submit name=Test value=Test></form></td></tr>';
$pg .= '<tr class=dl><td>'; $pg .= '<tr class=dl><td>';
$pg .= app_txt('2FA apps'); $pg .= app_txt('2FA apps');
$pg .= '<span class=urg>N.B.</span> if you wish to setup 2FA on more than one device,<br>'; $pg .= '<span class=urg>N.B.</span> if you wish to setup 2FA on more than one device,<br>';
@ -79,20 +80,32 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$pg .= 'so your should copy it and store it somewhere securely.<br>'; $pg .= 'so your should copy it and store it somewhere securely.<br>';
$pg .= 'For security reasons, the site will not show you an active <span class=urg>2FA Secret Key</span>.<br>'; $pg .= 'For security reasons, the site will not show you an active <span class=urg>2FA Secret Key</span>.<br>';
$pg .= '</td></tr>'; $pg .= '</td></tr>';
$pg .= '<tr class=dl><td>';
$pg .= makeForm('2fa');
$pg .= '<br>If you wish to cancel setting up 2FA, click here: ';
$pg .= '<input type=submit name=Cancel value=Cancel></form></td></tr>';
break; break;
case 'ok': case 'ok':
$pg .= '<tr class=dc><td>'; $pg .= '<tr class=dc><td>';
$pg .= '2FA is enabled on your account.<br><br>'; $pg .= '2FA is enabled on your account.<br><br>';
$pg .= 'If you wish to replace your Secret Key with a new one:<br><br>'; $pg .= 'If you wish to replace your Secret Key with a new one:<br><br>';
$pg .= makeForm('2fa');
$pg .= 'Current 2FA Value: <input name=Value value="" size=10> '; $pg .= 'Current 2FA Value: <input name=Value value="" size=10> ';
$pg .= '<input type=submit name=New value=New><span class=st1>*</span><br><br>'; $pg .= '<input type=submit name=New value=New><span class=st1>*</span>';
$pg .= '</form><br><br>';
$pg .= '<span class=st1>*</span>WARNING: replacing the Secret Key will disable 2FA<br>'; $pg .= '<span class=st1>*</span>WARNING: replacing the Secret Key will disable 2FA<br>';
$pg .= 'until you successfully test the new key,<br>'; $pg .= 'until you successfully test the new key,<br>';
$pg .= 'thus getting a new key is effectively the same as disabling 2FA.<br><br>'; $pg .= 'thus getting a new key is effectively the same as disabling 2FA.<br><br>';
$pg .= '</td></tr>'; $pg .= '</td></tr>';
$pg .= '<tr class=dc><td>';
$pg .= makeForm('2fa');
$pg .= 'If you wish to remove 2FA from your account,<br>';
$pg .= 'enter your App 2FA Value: <input name=Value value="" size=10><br>';
$pg .= 'then click remove: <input type=submit name=Remove value=Remove>';
$pg .= '</form></td></tr>';
break; break;
} }
$pg .= '</table></form>'; $pg .= '</table>';
$pg .= '</center></td></tr>'; $pg .= '</center></td></tr>';
$pg .= '<tr class=dl><td>'; $pg .= '<tr class=dl><td>';
@ -147,34 +160,52 @@ function set_2fa($data, $user, $tfa, $ans, $err)
# #
function do2fa($data, $user) function do2fa($data, $user)
{ {
$mailmode = '';
$err = ''; $err = '';
$setup = getparam('Setup', false); $setup = getparam('Setup', false);
$testemail = false;
if ($setup === 'Setup') if ($setup === 'Setup')
{ {
// rand() included as part of the entropy // rand() included as part of the entropy
$ans = get2fa($user, 'setup', rand(1073741824,2147483647), 0); $ans = get2fa($user, 'setup', rand(1073741824,2147483647), 0);
$testemail = true; $mailmode = 'Setup';
} }
else else
{ {
$value = getparam('Value', false); $can = getparam('Cancel', false);
$test = getparam('Test', false); if ($can === 'Cancel')
if ($test === 'Test' and $value !== null)
{ {
$ans = get2fa($user, 'test', 0, $value); $ans = get2fa($user, 'untest', 0, 0);
$testemail = true; $mailmode = 'Cancel';
} }
else else
{ {
$nw = getparam('New', false); $value = getparam('Value', false);
if ($nw === 'New' and $value !== null) $test = getparam('Test', false);
if ($test === 'Test' and $value !== null)
{ {
$ans = get2fa($user, 'new', rand(1073741824,2147483647), $value); $ans = get2fa($user, 'test', 0, $value);
$testemail = true; $mailmode = 'Test';
} }
else else
$ans = get2fa($user, '', 0, 0); {
$nw = getparam('New', false);
if ($nw === 'New' and $value !== null)
{
$ans = get2fa($user, 'new', rand(1073741824,2147483647), $value);
$mailmode = 'New';
}
else
{
$rem = getparam('Remove', false);
if ($rem === 'Remove' and $value !== null)
{
$ans = get2fa($user, 'remove', 0, $value);
$mailmode = 'Remove';
}
else
$ans = get2fa($user, '', 0, 0);
}
}
} }
} }
if ($ans['STATUS'] != 'ok') if ($ans['STATUS'] != 'ok')
@ -184,7 +215,7 @@ function do2fa($data, $user)
if (isset($ans['2fa_error'])) if (isset($ans['2fa_error']))
$err = $ans['2fa_error']; $err = $ans['2fa_error'];
if ($testemail and $err == '') if ($mailmode != '' and $err == '')
{ {
$ans2 = userSettings($user); $ans2 = userSettings($user);
if ($ans2['STATUS'] != 'ok') if ($ans2['STATUS'] != 'ok')
@ -199,12 +230,16 @@ function do2fa($data, $user)
$err = 'An error occurred, check your details below'; $err = 'An error occurred, check your details below';
else else
{ {
if ($setup === 'Setup') if ($mailmode === 'Setup')
twofaSetup($email, zeip(), $emailinfo); twofaSetup($email, zeip(), $emailinfo);
else if ($test === 'Test') else if ($mailmode === 'Test')
twofaEnabled($email, zeip(), $emailinfo); twofaEnabled($email, zeip(), $emailinfo);
else if ($nw === 'New') else if ($mailmode === 'New')
twofaSetup($email, zeip(), $emailinfo); twofaSetup($email, zeip(), $emailinfo);
else if ($mailmode === 'Cancel')
twofaCancel($email, zeip(), $emailinfo);
else if ($mailmode === 'Remove')
twofaRemove($email, zeip(), $emailinfo);
} }
} }
} }

5
src/ckdb.h

@ -55,7 +55,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "1.0.2" #define DB_VERSION "1.0.2"
#define CKDB_VERSION DB_VERSION"-1.233" #define CKDB_VERSION DB_VERSION"-1.240"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -2633,6 +2633,7 @@ extern bool check_2fa(USERS *users, int32_t value);
extern bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, extern bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root); char *inet, tv_t *cd, K_TREE *trf_root);
extern K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by, extern K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by,
char *code, char *inet, tv_t *cd, K_TREE *trf_root); char *code, char *inet, tv_t *cd, K_TREE *trf_root,
bool check);
#endif #endif

21
src/ckdb_cmd.c

@ -301,9 +301,24 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id,
else { else {
key = false; key = false;
sfa_status = "ok"; sfa_status = "ok";
sfa_error = "2FA Enabled";
} }
// Report sfa_error to web // Report sfa_error to web
ok = true; ok = true;
} else if (strcmp(action, "untest") == 0) {
// Can't untest if it's not ready to test
if ((users->databits & (USER_TOTPAUTH | USER_TEST2FA))
!= (USER_TOTPAUTH | USER_TEST2FA))
goto dame;
// since it's currently test, the value isn't required
u_new = remove_2fa(u_item, 0, by, code, inet, now,
trf_root, false);
if (u_new) {
ok = true;
sfa_status = EMPTY;
key = false;
sfa_error = "2FA Cancelled";
}
} else if (strcmp(action, "new") == 0) { } else if (strcmp(action, "new") == 0) {
// Can't new if 2FA isn't already present -> setup // Can't new if 2FA isn't already present -> setup
if ((users->databits & USER_TOTPAUTH) == 0) if ((users->databits & USER_TOTPAUTH) == 0)
@ -329,18 +344,22 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id,
// Can't remove if 2FA isn't already present // Can't remove if 2FA isn't already present
if (!(users->databits & (USER_TOTPAUTH | USER_TEST2FA))) if (!(users->databits & (USER_TOTPAUTH | USER_TEST2FA)))
goto dame; goto dame;
// remove requires value
value = (int32_t)atoi(transfer_data(i_value)); value = (int32_t)atoi(transfer_data(i_value));
if (!check_2fa(users, value)) { if (!check_2fa(users, value)) {
sfa_error = "Invalid code"; sfa_error = "Invalid code";
// Report sfa_error to web // Report sfa_error to web
ok = true; ok = true;
} else { } else {
/* already tested 2fa so don't retest, also,
* a retest will fail using the same value */
u_new = remove_2fa(u_item, value, by, code, u_new = remove_2fa(u_item, value, by, code,
inet, now, trf_root); inet, now, trf_root, false);
if (u_new) { if (u_new) {
ok = true; ok = true;
sfa_status = EMPTY; sfa_status = EMPTY;
key = false; key = false;
sfa_error = "2FA Removed";
} }
} }
} }

9
src/ckdb_crypt.c

@ -237,14 +237,17 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
} }
K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root) char *inet, tv_t *cd, K_TREE *trf_root, bool check)
{ {
K_ITEM *u_item = NULL; K_ITEM *u_item = NULL;
USERS *old_users, *users; USERS *old_users, *users;
bool ok, did = false; bool ok = true, did = false;
DATA_USERS(old_users, old_u_item); DATA_USERS(old_users, old_u_item);
ok = check_2fa(old_users, value); /* N.B. check_2fa will fail if it is called a second time
* with the same value */
if (check)
ok = check_2fa(old_users, value);
if (ok) { if (ok) {
K_WLOCK(users_free); K_WLOCK(users_free);
u_item = k_unlink_head(users_free); u_item = k_unlink_head(users_free);

Loading…
Cancel
Save