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,143 @@ 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
+ /*
472
+ Note: A webauthn callback (callback_type 2 or 5) is registered with both
473
+ "fido" and "webauthn" plugins. A fido callback (callback_type 1 or 4)
474
+ is registered only with "fido" plugin. And if user did not register any
475
+ callback (callback_type 0 or 3) then both plugin callbacks are re-set
476
+ to null.
477
+ */
478
+
479
+ register_callback (prx, " fido" , (callback_type % 3 ) > 1 );
480
+ register_callback (prx, " webauthn" , (callback_type % 3 ) > 0 );
481
+
482
+ /*
483
+ Note: This will be reset to value 0-2 when user deregisters
484
+ the callback or registers a new one.
485
+ */
486
+
487
+ drv.fido_callback = reinterpret_cast <Fido_Callback*>(callback_type + 3 );
488
+ }
489
+
490
+ private:
491
+
492
+ // The driver whose callback will be called by authentication plugins.
493
+
494
+ static sql::mysql::MySQL_Driver * driver;
495
+
496
+ /*
497
+ Callback function to be registered with authentication plugins.
498
+ If the current driver has a stored callback then it is being called.
499
+ */
500
+
501
+ static void callback_func (const char * msg)
502
+ {
503
+ if (!driver || !driver->fido_callback )
504
+ return ;
505
+ driver->webauthn_callback (msg);
506
+ }
507
+
508
+ static std::mutex mutex;
509
+ std::lock_guard<std::mutex> lock;
510
+
511
+ static
512
+ void register_callback (Proxy *proxy, std::string which, bool set_or_reset)
513
+ {
514
+ std::string plugin = " authentication_" + which + " _client" ;
515
+ std::string opt = (which == " webauthn" ?
516
+ " plugin_authentication_webauthn_client" : which) +
517
+ " _messages_callback" ;
518
+
519
+ try
520
+ {
521
+ proxy->plugin_option (MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
522
+ plugin.c_str (), opt.c_str (),
523
+ set_or_reset ? (const void *)callback_func : nullptr
524
+ );
525
+ }
526
+ catch (sql::MethodNotImplementedException &)
527
+ {
528
+ // Note: Ignore errors when re-setting the callback
529
+
530
+ if (!set_or_reset)
531
+ return ;
532
+
533
+ /*
534
+ If failed, plugin is not present, we ignore this fact for deprected
535
+ fido plugin.
536
+ */
537
+
538
+ if (" fido" != which)
539
+ throw ;
540
+ }
541
+ catch (sql::InvalidArgumentException &e)
542
+ {
543
+ if (!set_or_reset)
544
+ return ;
545
+
546
+ throw ::sql::SQLException (
547
+ " Failed to set fido message callback for "
548
+ + plugin + " plugin" );
549
+ }
550
+ };
551
+
552
+ };
553
+
554
+
555
+ std::mutex MySQL_Driver::WebAuthn_Callback_Setter::mutex;
556
+ sql::mysql::MySQL_Driver *MySQL_Driver::WebAuthn_Callback_Setter::driver
557
+ = nullptr ;
558
+
559
+
432
560
/*
433
561
We support :
434
562
- hostName
@@ -1412,62 +1540,14 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1412
1540
}
1413
1541
1414
1542
/*
1415
- * Helper class to simplify setting and resetting of the plugin callback.
1543
+ Note: If needed the setter will update callback functions registered with
1544
+ webauthn/fido authentication plugins to call the callback stored
1545
+ in the driver. It also protects the callbacks from being modified while
1546
+ connection is being made.
1416
1547
*/
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
-
1440
- }
1441
- catch (sql::InvalidArgumentException& e) {
1442
- throw ::sql::SQLUnsupportedOptionException (
1443
- " Failed to set fido message callback for authentication_fido_client plugin" ,
1444
- OPT_OCI_CONFIG_FILE
1445
- );
1446
- }
1447
- }
1448
- }
1449
-
1450
- ~Fido_Callback_Setter ()
1451
- {
1452
- if (fido_callback_instance && proxy)
1453
- {
1454
- try
1455
- {
1456
- proxy->plugin_option (MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
1457
- " authentication_fido_client" ,
1458
- " fido_messages_callback" ,
1459
- nullptr );
1460
- }
1461
- catch (...) {}
1462
- fido_callback_instance = nullptr ;
1463
- callback_mutex.unlock ();
1464
- }
1465
- }
1466
- };
1467
1548
1468
- Fido_Callback_Setter setter (
1469
- static_cast <MySQL_Driver*>(driver)->fido_callback ,
1470
- proxy.get ());
1549
+ MySQL_Driver::WebAuthn_Callback_Setter
1550
+ setter{*static_cast <MySQL_Driver*>(driver), proxy.get ()};
1471
1551
1472
1552
// Connect loop
1473
1553
{
0 commit comments