summaryrefslogtreecommitdiff
path: root/sql/sql_acl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r--sql/sql_acl.cc258
1 files changed, 215 insertions, 43 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 4c128a882c6..2f6c126e693 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -62,8 +62,9 @@ public:
char *user,*password;
ulong salt[2];
#ifdef HAVE_OPENSSL
- char *ssl_type, *ssl_cipher, *x509_issuer, *x509_subject;
-#endif
+ enum SSL_type ssl_type;
+ const char *ssl_cipher, *x509_issuer, *x509_subject;
+#endif /* HAVE_OPENSSL */
};
class ACL_DB :public ACL_ACCESS
@@ -204,13 +205,19 @@ int acl_init(bool dont_read_acl_tables)
user.password=get_field(&mem, table,2);
#ifdef HAVE_OPENSSL
DBUG_PRINT("info",("table->fields=%d",table->fields));
- if (table->fields >= 21) {
- user.ssl_type=get_field(&mem, table,17);
+ if (table->fields >= 21) { /* From 4.0.0 we have more fields */
+ if(!strcmp(get_field(&mem, table,17),"ANY"))
+ user.ssl_type=SSL_TYPE_ANY;
+ else if(!strcmp(get_field(&mem, table,17),"X509"))
+ user.ssl_type=SSL_TYPE_X509;
+ else if(!strcmp(get_field(&mem, table,17),"SPECIFIED"))
+ user.ssl_type=SSL_TYPE_SPECIFIED;
+ else user.ssl_type=SSL_TYPE_NONE;
user.ssl_cipher=get_field(&mem, table,18);
user.x509_issuer=get_field(&mem, table,19);
user.x509_subject=get_field(&mem, table,20);
}
-#endif
+#endif /* HAVE_OPENSSL */
if (user.password && (length=(uint) strlen(user.password)) == 8 &&
protocol_version == PROTOCOL_VERSION)
{
@@ -410,15 +417,14 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
}
-/* Get master privilges for user (priviliges for all tables) */
-
-
-uint acl_getroot(const char *host, const char *ip, const char *user,
+/* Get master privilges for user (priviliges for all tables). Required to connect */
+uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
bool old_ver)
{
uint user_access=NO_ACCESS;
*priv_user=(char*) user;
+ char *ptr=0;
if (!initialized)
return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */
@@ -440,7 +446,88 @@ uint acl_getroot(const char *host, const char *ip, const char *user,
!check_scramble(password,message,acl_user->salt,
(my_bool) old_ver)))
{
+#ifdef HAVE_OPENSSL
+#define vio (thd->net.vio)
+ /* In this point we know that user is allowed to connect
+ * from given host by given username/password pair. Now
+ * we check if SSL is required, if user is using SSL and
+ * if X509 certificate attributes are OK
+ */
+ switch(acl_user->ssl_type) {
+ case SSL_TYPE_NONE: /* SSL is not required to connect */
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ if(vio_type(vio) == VIO_TYPE_SSL)
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_X509: /* Client should have any valid certificate. */
+ /* Connections with non-valid certificates are dropped already
+ * in sslaccept() anyway, so we do not check validity here.
+ */
+ if(SSL_get_peer_certificate(vio->ssl_))
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_SPECIFIED: /* Client should have attributes as specified */
+ /* We do not check for absence of SSL because without SSL it does not
+ * pass all checks here anyway.
+ */
+ /* If cipher name is specified, we compare it to actual cipher in use */
+ if(acl_user->ssl_cipher)
+ DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
+ if(!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ break;
+ }
+ /* Prepare certificate (if exists) */
+ DBUG_PRINT("info",("checkpoint 1"));
+ X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ DBUG_PRINT("info",("checkpoint 2"));
+ /* If X509 issuer is speified, we check it... */
+ if(acl_user->x509_issuer)
+ {
+ DBUG_PRINT("info",("checkpoint 3"));
+ ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
+ acl_user->x509_issuer, ptr));
+ if(!strcmp(acl_user->x509_issuer,ptr))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ free(ptr);
+ break;
+ }
+ free(ptr);
+ }
+ DBUG_PRINT("info",("checkpoint 4"));
+ /* X509 subject is specified, we check it .. */
+ if(acl_user->x509_subject)
+ {
+ ptr = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
+ acl_user->x509_subject, ptr));
+ if(!strcmp(acl_user->x509_subject,ptr))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ free(ptr);
+ break;
+ }
+ free(ptr);
+ }
+ DBUG_PRINT("info",("checkpoint 5"));
+ break;
+ }
+ DBUG_PRINT("info",("checkpoint 6"));
+#else /* HAVE_OPENSSL */
user_access=acl_user->access;
+#endif /* HAVE_OPENSSL */
if (!acl_user->user)
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
break;
@@ -469,7 +556,14 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
}
static void acl_update_user(const char *user, const char *host,
- const char *password, uint privileges)
+ const char *password,
+#ifdef HAVE_OPENSSL
+ enum SSL_type ssl_type,
+ const char *ssl_cipher,
+ const char *x509_issuer,
+ const char *x509_subject,
+#endif /* HAVE_OPENSSL */
+ uint privileges)
{
for (uint i=0 ; i < acl_users.elements ; i++)
{
@@ -482,6 +576,12 @@ static void acl_update_user(const char *user, const char *host,
acl_user->host.hostname && !strcmp(host,acl_user->host.hostname))
{
acl_user->access=privileges;
+#ifdef HAVE_OPENSSL
+ acl_user->ssl_type=ssl_type;
+ acl_user->ssl_cipher=ssl_cipher;
+ acl_user->x509_issuer=x509_issuer;
+ acl_user->x509_subject=x509_subject;
+#endif /* HAVE_OPENSSL */
if (password)
{
if (!password[0])
@@ -500,7 +600,13 @@ static void acl_update_user(const char *user, const char *host,
static void acl_insert_user(const char *user, const char *host,
- const char *password,
+ const char *password,
+#ifdef HAVE_OPENSSL
+ enum SSL_type ssl_type,
+ const char *ssl_cipher,
+ const char *x509_issuer,
+ const char *x509_subject,
+#endif /* HAVE_OPENSSL */
uint privileges)
{
ACL_USER acl_user;
@@ -510,6 +616,12 @@ static void acl_insert_user(const char *user, const char *host,
acl_user.access=privileges;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
acl_user.hostname_length=(uint) strlen(acl_user.host.hostname);
+#ifdef HAVE_OPENSSL
+ acl_user.ssl_type=ssl_type;
+ acl_user.ssl_cipher=ssl_cipher;
+ acl_user.x509_issuer=x509_issuer;
+ acl_user.x509_subject=x509_subject;
+#endif /* HAVE_OPENSSL */
if (password)
{
acl_user.password=(char*) ""; // Just point at something
@@ -984,7 +1096,7 @@ static bool test_if_create_new_users(THD *thd)
** Handle GRANT commands
****************************************************************************/
-static int replace_user_table(TABLE *table, const LEX_USER &combo,
+static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
uint rights, char what, bool create_user)
{
int error = -1;
@@ -1044,7 +1156,40 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo,
table->field[i]->store(&what,1);
}
rights=get_access(table,3);
-
+#ifdef HAVE_OPENSSL
+ /* We write down SSL related ACL stuff */
+ DBUG_PRINT("info",("table->fields=%d",table->fields));
+ if (table->fields >= 21) { /* From 4.0.0 we have more fields */
+ switch (thd->lex.ssl_type) {
+ case SSL_TYPE_ANY:
+ table->field[17]->store("ANY",3);
+ table->field[18]->store("",0);
+ table->field[19]->store("",0);
+ table->field[20]->store("",0);
+ break;
+ case SSL_TYPE_X509:
+ table->field[17]->store("X509",4);
+ table->field[18]->store("",0);
+ table->field[19]->store("",0);
+ table->field[20]->store("",0);
+ break;
+ case SSL_TYPE_SPECIFIED:
+ table->field[17]->store("SPECIFIED",9);
+ if(thd->lex.ssl_cipher)
+ table->field[18]->store(thd->lex.ssl_cipher,strlen(thd->lex.ssl_cipher));
+ if(thd->lex.x509_issuer)
+ table->field[19]->store(thd->lex.x509_issuer,strlen(thd->lex.x509_issuer));
+ if(thd->lex.x509_subject)
+ table->field[20]->store(thd->lex.x509_subject,strlen(thd->lex.x509_subject));
+ break;
+ default:
+ table->field[17]->store("NONE",4);
+ table->field[18]->store("",0);
+ table->field[19]->store("",0);
+ table->field[20]->store("",0);
+ }
+ }
+#endif /* HAVE_OPENSSL */
if (old_row_exists)
{
/*
@@ -1078,9 +1223,23 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo,
if (!combo.password.str)
password=0; // No password given on command
if (old_row_exists)
- acl_update_user(combo.user.str,combo.host.str,password,rights);
+ acl_update_user(combo.user.str,combo.host.str,password,
+#ifdef HAVE_OPENSSL
+ thd->lex.ssl_type,
+ thd->lex.ssl_cipher,
+ thd->lex.x509_issuer,
+ thd->lex.x509_subject,
+#endif /* HAVE_OPENSSL */
+ rights);
else
- acl_insert_user(combo.user.str,combo.host.str,password,rights);
+ acl_insert_user(combo.user.str,combo.host.str,password,
+#ifdef HAVE_OPENSSL
+ thd->lex.ssl_type,
+ thd->lex.ssl_cipher,
+ thd->lex.x509_issuer,
+ thd->lex.x509_subject,
+#endif /* HAVE_OPENSSL */
+ rights);
}
table->file->index_end();
DBUG_RETURN(error);
@@ -1626,6 +1785,9 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
TABLE_LIST tables[3];
bool create_new_users=0;
DBUG_ENTER("mysql_table_grant");
+ DBUG_PRINT("info",("ssl_cipher=%s",thd->lex.ssl_cipher));
+ DBUG_PRINT("info",("x509_issuer=%s",thd->lex.x509_issuer));
+ DBUG_PRINT("info",("x509_subject=%s",thd->lex.x509_subject));
if (!initialized)
{
@@ -1715,9 +1877,10 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
continue;
}
/* Create user if needed */
- if (replace_user_table(tables[0].table,
- *Str,
- 0,
+ if (replace_user_table(thd,
+ tables[0].table,
+ *Str,
+ 0,
revoke_grant ? 'N' : 'Y',
create_new_users))
{
@@ -1810,7 +1973,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
pthread_mutex_unlock(&LOCK_grant);
if (!result)
send_ok(&thd->net);
- /* Tables are automaticly closed */
+ /* Tables are automatically closed */
DBUG_RETURN(result);
}
@@ -1871,7 +2034,8 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
result= -1;
continue;
}
- if ((replace_user_table(tables[0].table,
+ if ((replace_user_table(thd,
+ tables[0].table,
*Str,
(!db ? rights : 0), what, create_new_users)))
result= -1;
@@ -2332,6 +2496,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
uint counter, want_access,index;
int error = 0;
+ int ssl_options = 0;
ACL_USER *acl_user; ACL_DB *acl_db;
char buff[1024];
DBUG_ENTER("mysql_show_grants");
@@ -2426,30 +2591,37 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append('\'');
}
#ifdef HAVE_OPENSSL
-/* SSL grant stuff */
- DBUG_PRINT("info",("acl_user->ssl_type=%s",acl_user->ssl_type));
- DBUG_PRINT("info",("acl_user->ssl_cipher=%s",acl_user->ssl_cipher));
- DBUG_PRINT("info",("acl_user->x509_subject=%s",acl_user->x509_subject));
- DBUG_PRINT("info",("acl_user->x509_issuer=%s",acl_user->x509_issuer));
- if(acl_user->ssl_type) {
- if(!strcmp(acl_user->ssl_type,"ssl"))
- global.append(" REQUIRE SSL",12);
- else if(!strcmp(acl_user->ssl_type,"x509"))
- {
- global.append(" REQUIRE X509 ",14);
- if(acl_user->x509_issuer) {
- global.append("SUBJECT \"",9);
- global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
- global.append("\"",1);
- }
- if(acl_user->x509_subject) {
- global.append("ISSUER \"",8);
- global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
- global.append("\"",1);
- }
- }
+/* "show grants" SSL related stuff */
+ if(acl_user->ssl_type==SSL_TYPE_ANY)
+ global.append(" REQUIRE SSL",12);
+ else if(acl_user->ssl_type==SSL_TYPE_X509)
+ global.append(" REQUIRE X509",13);
+ else if(acl_user->ssl_type==SSL_TYPE_SPECIFIED)
+ {
+ global.append(" REQUIRE ",9);
+ if(acl_user->x509_issuer) {
+ if(ssl_options++)
+ global.append(" AND ",5);
+ global.append("ISSUER \"",8);
+ global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
+ global.append("\"",1);
+ }
+ if(acl_user->x509_subject) {
+ if(ssl_options++)
+ global.append(" AND ",5);
+ global.append("SUBJECT \"",9);
+ global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
+ global.append("\"",1);
}
-#endif
+ if(acl_user->ssl_cipher) {
+ if(ssl_options++)
+ global.append(" AND ",5);
+ global.append("CIPHER \"",8);
+ global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
+ global.append("\"",1);
+ }
+ }
+#endif /* HAVE_OPENSSL */
if (want_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18);
thd->packet.length(0);