95
95
# define ER_MUST_CHANGE_PASSWORD_LOGIN 1820
96
96
#endif
97
97
98
- std::mutex callback_mutex;
99
-
100
- sql::Fido_Callback * fido_callback_instance = nullptr ;
101
98
102
99
bool oci_plugin_is_loaded = false ;
103
100
104
- static void fido_callback_func (const char * msg)
105
- {
106
- if (!fido_callback_instance)
107
- return ;
108
- (*fido_callback_instance)(msg);
109
- }
110
-
111
101
112
102
namespace sql
113
103
{
@@ -414,6 +404,7 @@ bool get_connection_option(const sql::SQLString optionName,
414
404
return false ;
415
405
}
416
406
407
+
417
408
struct Prio
418
409
{
419
410
uint16_t prio;
@@ -429,6 +420,133 @@ struct Prio
429
420
}
430
421
};
431
422
423
+
424
+ /*
425
+ A callback setter object arranges for correct WebAuthn/Fido authentication
426
+ callbacks to be used by the correpsonding clientlib authentication plugin.
427
+
428
+ If a user has registered a callback with a driver that creates a connection
429
+ then a callback function is registered with authentication plugins which will
430
+ call the callback stored in the driver.
431
+
432
+ The callback function registered with authentication plugins must be changed
433
+ depending on which driver is used to create a connection. A callback setter
434
+ object makes necessary changes when it detects that the current driver passed
435
+ to its ctor is different from the one used last time.
436
+
437
+ While exists, callback setter also prevents modification of authentication
438
+ plugin callbacks by concurrent threads.
439
+ */
440
+
441
+ struct MySQL_Driver ::WebAuthn_Callback_Setter
442
+ {
443
+ using Proxy = NativeAPI::NativeConnectionWrapper;
444
+
445
+ WebAuthn_Callback_Setter (MySQL_Driver &drv, Proxy *prx)
446
+ : lock{mutex}
447
+ {
448
+ /*
449
+ Note: Meaning of callback type value:
450
+
451
+ 0 or 3 = no callback
452
+ 1 or 4 = webauthn only callback
453
+ 2 or 5 = webauthn and fido callback
454
+
455
+ Values 3,4,5 indicate that the callback function has been already
456
+ (de-)registered with the plugin(s).
457
+ */
458
+
459
+ auto callback_type = reinterpret_cast <intptr_t >(drv.fido_callback );
460
+
461
+ /*
462
+ Do nothing if we use the same driver as last time nad (de-)registration
463
+ was already done.
464
+ */
465
+
466
+ if ((2 < callback_type) && (driver == &drv))
467
+ return ;
468
+
469
+ driver = &drv; // Set current driver.
470
+
471
+ register_callback (prx, " fido" , callback_type % 3 > 1 );
472
+ register_callback (prx, " webauthn" , callback_type % 3 > 0 );
473
+
474
+ /*
475
+ Note: This will be reset to value 0-2 when user deregisters
476
+ the callback or registers a new one.
477
+ */
478
+
479
+ drv.fido_callback = reinterpret_cast <Fido_Callback*>(callback_type + 3 );
480
+ }
481
+
482
+ private:
483
+
484
+ // The driver whose callback will be called by authentication plugins.
485
+
486
+ static sql::mysql::MySQL_Driver * driver;
487
+
488
+ /*
489
+ Callback function to be registered with authentication plugins.
490
+ If the current driver has a stored callback then it is being called.
491
+ */
492
+
493
+ static void callback_func (const char * msg)
494
+ {
495
+ if (!driver || !driver->fido_callback )
496
+ return ;
497
+ driver->webauthn_callback (msg);
498
+ }
499
+
500
+ static std::mutex mutex;
501
+ std::lock_guard<std::mutex> lock;
502
+
503
+ static
504
+ void register_callback (Proxy *proxy, std::string which, bool set_or_reset)
505
+ {
506
+ std::string plugin = " authentication_" + which + " _client" ;
507
+ std::string opt = which + " _messages_callback" ;
508
+
509
+ try
510
+ {
511
+ proxy->plugin_option (MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
512
+ plugin.c_str (), opt.c_str (),
513
+ set_or_reset ? (const void *)callback_func : nullptr
514
+ );
515
+ }
516
+ catch (sql::MethodNotImplementedException &)
517
+ {
518
+ // Note: Ignore errors when re-setting the callback
519
+
520
+ if (!set_or_reset)
521
+ return ;
522
+
523
+ /*
524
+ If failed, plugin is not present, we ignore this fact for deprected
525
+ fido plugin.
526
+ */
527
+
528
+ if (" fido" != which)
529
+ throw ;
530
+ }
531
+ catch (sql::InvalidArgumentException &e)
532
+ {
533
+ if (!set_or_reset)
534
+ return ;
535
+
536
+ throw ::sql::SQLException (
537
+ " Failed to set fido message callback for "
538
+ + plugin + " plugin" );
539
+ }
540
+ };
541
+
542
+ };
543
+
544
+
545
+ std::mutex MySQL_Driver::WebAuthn_Callback_Setter::mutex;
546
+ sql::mysql::MySQL_Driver *MySQL_Driver::WebAuthn_Callback_Setter::driver
547
+ = nullptr ;
548
+
549
+
432
550
/*
433
551
We support :
434
552
- hostName
@@ -1412,75 +1530,14 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1412
1530
}
1413
1531
1414
1532
/*
1415
- * Helper class to simplify setting and resetting of the plugin callback.
1533
+ Note: If needed the setter will update callback functions registered with
1534
+ webauthn/fido authentication plugins to call the callback stored
1535
+ in the driver. It also protects the callbacks from being modified while
1536
+ connection is being made.
1416
1537
*/
1417
- struct Fido_Callback_Setter
1418
- {
1419
- NativeAPI::NativeConnectionWrapper *proxy = nullptr ;
1420
-
1421
- /*
1422
- * Construct the setter using the callback and proxy.
1423
- */
1424
- Fido_Callback_Setter (Fido_Callback *callback,
1425
- NativeAPI::NativeConnectionWrapper *_proxy) :
1426
- proxy (_proxy)
1427
- {
1428
- if (proxy && callback && *callback)
1429
- {
1430
- callback_mutex.lock ();
1431
- try
1432
- {
1433
- fido_callback_instance = callback;
1434
- proxy->plugin_option (MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
1435
- " authentication_fido_client" ,
1436
- " fido_messages_callback" ,
1437
- (const void *)fido_callback_func
1438
- );
1439
- } catch (sql::MethodNotImplementedException &) {
1440
- // If failed, authentication_fido_client is no longer present... skip
1441
- } catch (sql::InvalidArgumentException &e) {
1442
- throw ::sql::SQLException (
1443
- " Failed to set fido message callback for "
1444
- " authentication_fido_client plugin" );
1445
- }
1446
-
1447
- try
1448
- {
1449
- fido_callback_instance = callback;
1450
- proxy->plugin_option (MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
1451
- " authentication_webauthn_client" ,
1452
- " webauthn_messages_callback" ,
1453
- (const void *)fido_callback_func);
1454
-
1455
- }
1456
- catch (sql::InvalidArgumentException& e) {
1457
- throw ::sql::SQLException (
1458
- " Failed to set webauthn message callback for "
1459
- " authentication_webauthn_client plugin" );
1460
- }
1461
- }
1462
- }
1463
-
1464
- ~Fido_Callback_Setter ()
1465
- {
1466
- if (fido_callback_instance && proxy)
1467
- {
1468
- try
1469
- {
1470
- proxy->plugin_option (MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
1471
- " authentication_webauthn_client" ,
1472
- " webauthn_messages_callback" , nullptr );
1473
- }
1474
- catch (...) {}
1475
- fido_callback_instance = nullptr ;
1476
- callback_mutex.unlock ();
1477
- }
1478
- }
1479
- };
1480
1538
1481
- Fido_Callback_Setter setter (
1482
- static_cast <MySQL_Driver*>(driver)->fido_callback ,
1483
- proxy.get ());
1539
+ MySQL_Driver::WebAuthn_Callback_Setter
1540
+ setter{*static_cast <MySQL_Driver*>(driver), proxy.get ()};
1484
1541
1485
1542
// Connect loop
1486
1543
{
0 commit comments