Skip to content

Commit 588be34

Browse files
committed
Forward connection certificate to audit plugin
Summary: Forward the connection certificate to the audit plugin. The connection certificate can then be parsed by the audit plugin and handled appropriately. It made more sense for the certificate to live in the connection events, since they generally don't change between every general event, so the move was done. This is done by caching a BUF_MEM struct on the THD object. Since it's not possible to change certificates on the same connection, this caching should be correct. The BUF_MEM is released on THD::release_resources. If upstream bumps the MYSQL_AUDIT_INTERFACE_VERSION, we should bump ours to be greater or equal to it. Test Plan: Test with plugin to see that certificate information is present. Reviewers: jtolmer, jkedgar Reviewed By: jkedgar Subscribers: webscalesql-eng, anca Differential Revision: https://reviews.facebook.net/D52263
1 parent a619992 commit 588be34

File tree

11 files changed

+146
-87
lines changed

11 files changed

+146
-87
lines changed

include/mysql/plugin_audit.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
#define MYSQL_AUDIT_CLASS_MASK_SIZE 1
2727

28-
#define MYSQL_AUDIT_INTERFACE_VERSION 0x0303
28+
#define MYSQL_AUDIT_INTERFACE_VERSION 0x0304
2929

3030

3131
/*************************************************************************
@@ -69,8 +69,6 @@ struct mysql_event_general
6969
unsigned int database_length;
7070
/* Added in version 0x303 */
7171
unsigned long long affected_rows;
72-
const char *connection_certificate;
73-
unsigned int connection_certificate_length;
7472
const char *query_attributes;
7573
unsigned int query_attributes_length;
7674
};
@@ -109,6 +107,9 @@ struct mysql_event_connection
109107
unsigned int ip_length;
110108
const char *database;
111109
unsigned int database_length;
110+
/* Added in version 0x304 */
111+
const char *connection_certificate;
112+
unsigned int connection_certificate_length;
112113
};
113114

114115

include/mysql/plugin_audit.h.pp

+2-2
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,6 @@
287287
const char *database;
288288
unsigned int database_length;
289289
unsigned long long affected_rows;
290-
const char *connection_certificate;
291-
unsigned int connection_certificate_length;
292290
const char *query_attributes;
293291
unsigned int query_attributes_length;
294292
};
@@ -311,6 +309,8 @@
311309
unsigned int ip_length;
312310
const char *database;
313311
unsigned int database_length;
312+
const char *connection_certificate;
313+
unsigned int connection_certificate_length;
314314
};
315315
struct st_mysql_audit
316316
{

sql/sql_acl.cc

+4
Original file line numberDiff line numberDiff line change
@@ -11265,6 +11265,10 @@ acl_authenticate(THD *thd, uint com_change_user_pkt_len)
1126511265
DBUG_RETURN(1);
1126611266
}
1126711267

11268+
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
11269+
thd->set_connection_certificate();
11270+
#endif
11271+
1126811272
if (unlikely(mpvio.acl_user && mpvio.acl_user->password_expired
1126911273
&& !(mpvio.client_capabilities & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)
1127011274
&& disconnect_on_expired_password))

sql/sql_audit.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ static void general_class_handler(THD *thd, uint event_subtype, va_list ap)
9090
event.general_ip= va_arg(ap, MYSQL_LEX_STRING);
9191
event.database= va_arg(ap, const char *);
9292
event.database_length= va_arg(ap, unsigned int);
93-
event.connection_certificate= va_arg(ap, const char*);
94-
event.connection_certificate_length= va_arg(ap, unsigned int);
9593
event.query_attributes= va_arg(ap, const char*);
9694
event.query_attributes_length= va_arg(ap, unsigned int);
9795
event.query_id= (unsigned long long) thd->query_id;
@@ -119,6 +117,8 @@ static void connection_class_handler(THD *thd, uint event_subclass, va_list ap)
119117
event.ip_length= va_arg(ap, unsigned int);
120118
event.database= va_arg(ap, const char *);
121119
event.database_length= va_arg(ap, unsigned int);
120+
event.connection_certificate= va_arg(ap, const char*);
121+
event.connection_certificate_length= va_arg(ap, unsigned int);
122122
event_class_dispatch(thd, MYSQL_AUDIT_CONNECTION_CLASS, &event);
123123
}
124124

sql/sql_audit.h

+16-17
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ void mysql_audit_general_log(THD *thd, const char *cmd, uint cmdlen,
7979
longlong affectrows= 0;
8080
int error_code= 0;
8181
char user_buff[MAX_USER_HOST_SIZE + 1];
82-
uint userlen, databaselen, certlen, queryattrlen;
83-
const char *user, *database, *cert, *queryattr;
82+
uint userlen, databaselen, queryattrlen;
83+
const char *user, *database, *queryattr;
8484
time_t time= (time_t) thd->start_time.tv_sec;
8585

8686
if (thd)
@@ -113,8 +113,6 @@ void mysql_audit_general_log(THD *thd, const char *cmd, uint cmdlen,
113113
sql_command.length= sql_statement_names[thd->lex->sql_command].length;
114114
database= thd->db;
115115
databaselen= thd->db_length;
116-
cert= 0;
117-
certlen= 0;
118116
queryattr= thd->query_attrs();
119117
queryattrlen= thd->query_attrs_length();
120118
}
@@ -128,8 +126,6 @@ void mysql_audit_general_log(THD *thd, const char *cmd, uint cmdlen,
128126
sql_command= empty;
129127
database= 0;
130128
databaselen= 0;
131-
cert= 0;
132-
certlen= 0;
133129
queryattr= 0;
134130
queryattrlen= 0;
135131
}
@@ -140,7 +136,7 @@ void mysql_audit_general_log(THD *thd, const char *cmd, uint cmdlen,
140136
error_code, time, user, userlen, cmd, cmdlen, query.str,
141137
query.length, clientcs, resultrows, affectrows,
142138
sql_command, host, external_user, ip, database,
143-
databaselen, cert, certlen, queryattr, queryattrlen);
139+
databaselen, queryattr, queryattrlen);
144140
}
145141
#endif
146142
}
@@ -167,8 +163,8 @@ void mysql_audit_general(THD *thd, uint event_subtype,
167163
{
168164
time_t time= my_time(0);
169165
uint msglen= msg ? strlen(msg) : 0;
170-
uint userlen, databaselen, certlen, queryattrlen;
171-
const char *user, *database, *cert, *queryattr;
166+
uint userlen, databaselen, queryattrlen;
167+
const char *user, *database, *queryattr;
172168
char user_buff[MAX_USER_HOST_SIZE];
173169
CSET_STRING query;
174170
MYSQL_LEX_STRING ip, host, external_user, sql_command;
@@ -213,8 +209,6 @@ void mysql_audit_general(THD *thd, uint event_subtype,
213209
sql_command.length= sql_statement_names[thd->lex->sql_command].length;
214210
database= thd->db;
215211
databaselen= thd->db_length;
216-
cert= 0;
217-
certlen= 0;
218212
queryattr= thd->query_attrs();
219213
queryattrlen= thd->query_attrs_length();
220214
}
@@ -230,8 +224,6 @@ void mysql_audit_general(THD *thd, uint event_subtype,
230224
affectrows= 0;
231225
database= 0;
232226
databaselen= 0;
233-
cert= 0;
234-
certlen= 0;
235227
queryattr= 0;
236228
queryattrlen= 0;
237229
}
@@ -241,7 +233,7 @@ void mysql_audit_general(THD *thd, uint event_subtype,
241233
query.str(), query.length(), query.charset(),
242234
resultrows, affectrows, sql_command, host,
243235
external_user, ip, database, databaselen,
244-
cert, certlen, queryattr, queryattrlen);
236+
queryattr, queryattrlen);
245237
}
246238
#endif
247239
}
@@ -259,7 +251,10 @@ void mysql_audit_general(THD *thd, uint event_subtype,
259251
(thd)->security_ctx->get_host()->length(),\
260252
(thd)->security_ctx->get_ip()->ptr(),\
261253
(thd)->security_ctx->get_ip()->length(),\
262-
(thd)->db, (thd)->db ? strlen((thd)->db) : 0)
254+
(thd)->db, (thd)->db ? strlen((thd)->db) : 0,\
255+
(thd)->connection_certificate(),\
256+
(thd)->connection_certificate_length());
257+
263258

264259
#define MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT(thd, errcode)\
265260
mysql_audit_notify(\
@@ -275,7 +270,9 @@ void mysql_audit_general(THD *thd, uint event_subtype,
275270
(thd)->security_ctx->get_host()->length(),\
276271
(thd)->security_ctx->get_ip()->ptr(),\
277272
(thd)->security_ctx->get_ip()->length(),\
278-
(thd)->db, (thd)->db ? strlen((thd)->db) : 0)
273+
(thd)->db, (thd)->db ? strlen((thd)->db) : 0,\
274+
(thd)->connection_certificate(),\
275+
(thd)->connection_certificate_length());
279276

280277
#define MYSQL_AUDIT_NOTIFY_CONNECTION_CHANGE_USER(thd) mysql_audit_notify(\
281278
(thd), MYSQL_AUDIT_CONNECTION_CLASS, MYSQL_AUDIT_CONNECTION_CHANGE_USER,\
@@ -290,6 +287,8 @@ void mysql_audit_general(THD *thd, uint event_subtype,
290287
(thd)->security_ctx->get_host()->length(),\
291288
(thd)->security_ctx->get_ip()->ptr(),\
292289
(thd)->security_ctx->get_ip()->length(),\
293-
(thd)->db, (thd)->db ? strlen((thd)->db) : 0)
290+
(thd)->db, (thd)->db ? strlen((thd)->db) : 0,\
291+
(thd)->connection_certificate(),\
292+
(thd)->connection_certificate_length());
294293

295294
#endif /* SQL_AUDIT_INCLUDED */

sql/sql_class.cc

+80
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,7 @@ THD::THD(bool enable_plugins)
978978
#endif /* defined(ENABLED_DEBUG_SYNC) */
979979
m_enable_plugins(enable_plugins),
980980
owned_gtid_set(global_sid_map),
981+
connection_certificate_buf(NULL),
981982
main_da(0, false),
982983
m_stmt_da(&main_da),
983984
conn_timeout_err_msg(NULL),
@@ -1550,6 +1551,9 @@ void THD::change_user(void)
15501551
(my_hash_free_key) free_user_var, 0);
15511552
sp_cache_clear(&sp_proc_cache);
15521553
sp_cache_clear(&sp_func_cache);
1554+
#if defined(HAVE_OPENSSL)
1555+
reset_connection_certificate();
1556+
#endif
15531557
}
15541558

15551559

@@ -1656,6 +1660,9 @@ void THD::release_resources()
16561660
net_end(&net);
16571661
net.vio= NULL;
16581662
}
1663+
#if defined(HAVE_OPENSSL)
1664+
reset_connection_certificate();
1665+
#endif
16591666
#endif
16601667
mysql_mutex_unlock(&LOCK_thd_data);
16611668

@@ -4938,6 +4945,79 @@ void THD::get_definer(LEX_USER *definer)
49384945
get_default_definer(this, definer);
49394946
}
49404947

4948+
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4949+
void THD::set_connection_certificate() {
4950+
DBUG_ASSERT(connection_certificate_buf == nullptr);
4951+
connection_certificate_buf = get_peer_cert_info(false);
4952+
}
4953+
4954+
void THD::reset_connection_certificate() {
4955+
if (connection_certificate_buf) {
4956+
BUF_MEM_free(connection_certificate_buf);
4957+
connection_certificate_buf = nullptr;
4958+
}
4959+
}
4960+
4961+
const char *THD::connection_certificate() const {
4962+
return connection_certificate_buf ?
4963+
connection_certificate_buf->data : nullptr;
4964+
}
4965+
4966+
uint32 THD::connection_certificate_length() const {
4967+
return connection_certificate_buf ? connection_certificate_buf->length : 0;
4968+
}
4969+
4970+
BUF_MEM *THD::get_peer_cert_info(bool display)
4971+
{
4972+
if (!vio_ok() || !net.vio->ssl_arg) {
4973+
return NULL;
4974+
}
4975+
4976+
SSL *ssl= (SSL*) net.vio->ssl_arg;
4977+
4978+
// extract user cert ref from the thread
4979+
X509 *cert= SSL_get_peer_certificate(ssl);
4980+
4981+
if (!cert) {
4982+
return NULL;
4983+
}
4984+
4985+
// Create new X509 buffer abstraction
4986+
BIO *bio = BIO_new(BIO_s_mem());
4987+
if (!bio) {
4988+
X509_free(cert);
4989+
return NULL;
4990+
}
4991+
4992+
// Print the certificate to the buffer
4993+
int status;
4994+
if (display) {
4995+
status = X509_print(bio, cert);
4996+
} else {
4997+
status = PEM_write_bio_X509(bio, cert);
4998+
}
4999+
5000+
if (status != 1) {
5001+
BIO_free(bio);
5002+
X509_free(cert);
5003+
return NULL;
5004+
}
5005+
5006+
// decouple buffer and close bio object
5007+
BUF_MEM *bufmem;
5008+
BIO_get_mem_ptr(bio, &bufmem);
5009+
(void) BIO_set_close(bio, BIO_NOCLOSE);
5010+
BIO_free(bio);
5011+
X509_free(cert);
5012+
5013+
if (bufmem->length) {
5014+
return bufmem;
5015+
}
5016+
5017+
BUF_MEM_free(bufmem);
5018+
return NULL;
5019+
}
5020+
#endif
49415021

49425022
/**
49435023
Mark transaction to rollback and mark error as fatal to a sub-statement.

sql/sql_class.h

+19
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
#include "sql_data_change.h"
5353
#include "my_atomic.h"
5454

55+
#include <openssl/pem.h>
56+
5557
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
5658

5759
/**
@@ -4483,6 +4485,23 @@ class THD :public MDL_context_owner,
44834485
return query_attrs_string.length();
44844486
}
44854487

4488+
private:
4489+
BUF_MEM *connection_certificate_buf;
4490+
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4491+
void reset_connection_certificate();
4492+
public:
4493+
void set_connection_certificate();
4494+
const char *connection_certificate() const;
4495+
uint32 connection_certificate_length() const;
4496+
// The caller should take ownership of the BUF_MEM pointer. If display is
4497+
// set to true, the buffer will contain the certificate encoded in a human
4498+
// readable format, which can be used for display in information schema.
4499+
// Otherwise, it is encoded in the PEM format.
4500+
//
4501+
// Free this using the function BUF_MEM_free.
4502+
BUF_MEM *get_peer_cert_info(bool display);
4503+
#endif
4504+
44864505
#ifndef DBUG_OFF
44874506
private:
44884507
int gis_debug; // Storage for "SELECT ST_GIS_DEBUG(param);"

0 commit comments

Comments
 (0)