diff options
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r-- | sql/sql_acl.cc | 803 |
1 files changed, 620 insertions, 183 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index edfc2ceeab8..0b02935e96c 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,15 +1,15 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - +/* Copyright (C) 2000 MySQL AB + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -29,24 +29,25 @@ #include "sql_acl.h" #include "hash_filo.h" #include <m_ctype.h> +#include <assert.h> #include <stdarg.h> -/* - ACL_HOST is used if no host is specified - */ - struct acl_host_and_ip { char *hostname; long ip,ip_mask; // Used with masked ip:s }; + class ACL_ACCESS { public: ulong sort; - uint access; + ulong access; }; + +/* ACL_HOST is used if no host is specified */ + class ACL_HOST :public ACL_ACCESS { public: @@ -54,15 +55,22 @@ public: char *db; }; + class ACL_USER :public ACL_ACCESS { public: acl_host_and_ip host; uint hostname_length; + USER_RESOURCES user_resource; char *user,*password; ulong salt[2]; +#ifdef HAVE_OPENSSL + enum SSL_type ssl_type; + const char *ssl_cipher, *x509_issuer, *x509_subject; +#endif /* HAVE_OPENSSL */ }; + class ACL_DB :public ACL_ACCESS { public: @@ -70,14 +78,16 @@ public: char *user,*db; }; + class acl_entry :public hash_filo_element { public: - uint access; + ulong access; uint16 length; char key[1]; // Key will be stored here }; + static byte* acl_entry_get_key(acl_entry *entry,uint *length, my_bool not_used __attribute__((unused))) { @@ -95,7 +105,7 @@ static HASH acl_check_hosts, hash_tables; static DYNAMIC_ARRAY acl_wild_hosts; static hash_filo *acl_cache; static uint grant_version=0; -static uint get_access(TABLE *form,uint fieldnr); +static ulong get_access(TABLE *form,uint fieldnr); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); @@ -106,7 +116,33 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname); static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, const char *ip); -int acl_init(bool dont_read_acl_tables) +extern char uc_update_queries[SQLCOM_END]; + +static void init_update_queries(void) +{ + uc_update_queries[SQLCOM_CREATE_TABLE]=1; + uc_update_queries[SQLCOM_CREATE_INDEX]=1; + uc_update_queries[SQLCOM_ALTER_TABLE]=1; + uc_update_queries[SQLCOM_UPDATE]=1; + uc_update_queries[SQLCOM_INSERT]=1; + uc_update_queries[SQLCOM_INSERT_SELECT]=1; + uc_update_queries[SQLCOM_DELETE]=1; + uc_update_queries[SQLCOM_TRUNCATE]=1; + uc_update_queries[SQLCOM_DROP_TABLE]=1; + uc_update_queries[SQLCOM_LOAD]=1; + uc_update_queries[SQLCOM_CREATE_DB]=1; + uc_update_queries[SQLCOM_DROP_DB]=1; + uc_update_queries[SQLCOM_REPLACE]=1; + uc_update_queries[SQLCOM_REPLACE_SELECT]=1; + uc_update_queries[SQLCOM_RENAME_TABLE]=1; + uc_update_queries[SQLCOM_BACKUP_TABLE]=1; + uc_update_queries[SQLCOM_RESTORE_TABLE]=1; + uc_update_queries[SQLCOM_DELETE_MULTI]=1; + uc_update_queries[SQLCOM_DROP_INDEX]=1; + uc_update_queries[SQLCOM_MULTI_UPDATE]=1; +} + +int acl_init(bool dont_read_acl_tables) { THD *thd; TABLE_LIST tables[3]; @@ -128,7 +164,8 @@ int acl_init(bool dont_read_acl_tables) thd->mysys_var=my_thread_var; thd->current_tablenr=0; thd->open_tables=0; - thd->db=my_strdup("mysql",MYF(0)); + thd->db= my_strdup("mysql",MYF(0)); + thd->db_length=5; // Safety bzero((char*) &tables,sizeof(tables)); tables[0].name=tables[0].real_name=(char*) "host"; tables[1].name=tables[1].real_name=(char*) "user"; @@ -163,10 +200,10 @@ int acl_init(bool dont_read_acl_tables) { ACL_HOST host; update_hostname(&host.host,get_field(&mem, table,0)); - host.db=get_field(&mem, table,1); - host.access=get_access(table,2); - host.access=fix_rights_for_db(host.access); - host.sort=get_sort(2,host.host.hostname,host.db); + host.db= get_field(&mem, table,1); + host.access= get_access(table,2); + host.access= fix_rights_for_db(host.access); + host.sort= get_sort(2,host.host.hostname,host.db); #ifndef TO_BE_REMOVED if (table->fields == 8) { // Without grant @@ -191,6 +228,7 @@ int acl_init(bool dont_read_acl_tables) protocol_version=9; /* purecov: tested */ } + DBUG_PRINT("info",("user table fields: %d",table->fields)); allow_all_hosts=0; while (!(read_record_info.read_record(&read_record_info))) { @@ -203,7 +241,7 @@ int acl_init(bool dont_read_acl_tables) protocol_version == PROTOCOL_VERSION) { sql_print_error( - "Found old style password for user '%s'. Ignoring user. (You may want to restart using --old-protocol)", + "Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)", user.user ? user.user : ""); /* purecov: tested */ } else if (length % 8) // This holds true for passwords @@ -212,19 +250,60 @@ int acl_init(bool dont_read_acl_tables) "Found invalid password for user: '%s@%s'; Ignoring user", user.user ? user.user : "", user.host.hostname ? user.host.hostname : ""); /* purecov: tested */ - continue; /* purecov: tested */ + continue; /* purecov: tested */ } get_salt_from_password(user.salt,user.password); user.access=get_access(table,3); user.sort=get_sort(2,user.host.hostname,user.user); - user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0; -#ifndef TO_BE_REMOVED - if (table->fields <= 13) - { // Without grant - if (user.access & CREATE_ACL) - user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + user.hostname_length= (user.host.hostname ? + (uint) strlen(user.host.hostname) : 0); + if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ + { +#ifdef HAVE_OPENSSL + char *ssl_type=get_field(&mem, table, 24); + if (!ssl_type) + user.ssl_type=SSL_TYPE_NONE; + else if (!strcmp(ssl_type, "ANY")) + user.ssl_type=SSL_TYPE_ANY; + else if (!strcmp(ssl_type, "X509")) + user.ssl_type=SSL_TYPE_X509; + else /* !strcmp(ssl_type, "SPECIFIED") */ + user.ssl_type=SSL_TYPE_SPECIFIED; + + user.ssl_cipher= get_field(&mem, table, 25); + user.x509_issuer= get_field(&mem, table, 26); + user.x509_subject= get_field(&mem, table, 27); +#endif + char *ptr = get_field(&mem, table, 28); + user.user_resource.questions=atoi(ptr); + ptr = get_field(&mem, table, 29); + user.user_resource.updates=atoi(ptr); + ptr = get_field(&mem, table, 30); + user.user_resource.connections=atoi(ptr); + if (user.user_resource.questions || user.user_resource.updates || + user.user_resource.connections) + mqh_used=1; } + else + { +#ifdef HAVE_OPENSSL + user.ssl_type=SSL_TYPE_NONE; +#endif + bzero(&(user.user_resource),sizeof(user.user_resource)); +#ifndef TO_BE_REMOVED + if (table->fields <= 13) + { // Without grant + if (user.access & CREATE_ACL) + user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + } + /* Convert old privileges */ + user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; + if (user.access & FILE_ACL) + user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + if (user.access & PROCESS_ACL) + user.access|= SUPER_ACL | EXECUTE_ACL; #endif + } VOID(push_dynamic(&acl_users,(gptr) &user)); if (!user.host.hostname || user.host.hostname[0] == wild_many && !user.host.hostname[1]) @@ -262,6 +341,7 @@ int acl_init(bool dont_read_acl_tables) init_check_host(); mysql_unlock_tables(thd, lock); + init_update_queries(); thd->version--; // Force close to free memory close_thread_tables(thd); delete thd; @@ -334,31 +414,38 @@ void acl_reload(void) } -/* Get all access bits from table after fieldnr */ +/* + Get all access bits from table after fieldnr + We know that the access privileges ends when there is no more fields + or the field is not an enum with two elements. +*/ -static uint get_access(TABLE *form,uint fieldnr) +static ulong get_access(TABLE *form, uint fieldnr) { - uint access_bits=0,bit; + ulong access_bits=0,bit; char buff[2]; String res(buff,sizeof(buff)); Field **pos; - for (pos=form->field+fieldnr,bit=1 ; *pos ; pos++ , bit<<=1) + for (pos=form->field+fieldnr, bit=1; + *pos && (*pos)->real_type() == FIELD_TYPE_ENUM && + ((Field_enum*) (*pos))->typelib->count == 2 ; + pos++ , bit<<=1) { (*pos)->val_str(&res,&res); if (toupper(res[0]) == 'Y') - access_bits|=bit; + access_bits|= bit; } return access_bits; } /* - return a number which, if sorted 'desc', puts strings in this order: - no wildcards - wildcards - empty string - */ + Return a number which, if sorted 'desc', puts strings in this order: + no wildcards + wildcards + empty string +*/ static ulong get_sort(uint count,...) { @@ -398,18 +485,22 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) } -/* Get master privilges for user (priviliges for all tables) */ - +/* + Get master privilges for user (priviliges for all tables). + Required before connecting to MySQL +*/ -uint acl_getroot(const char *host, const char *ip, const char *user, - const char *password,const char *message,char **priv_user, - bool old_ver) +ulong 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, USER_RESOURCES *mqh) { - uint user_access=NO_ACCESS; + ulong user_access=NO_ACCESS; *priv_user=(char*) user; + char *ptr=0; + bzero(mqh,sizeof(USER_RESOURCES)); if (!initialized) - return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */ + return (ulong) ~NO_ACCESS; // If no data allow anything /* purecov: tested */ VOID(pthread_mutex_lock(&acl_cache->lock)); /* @@ -428,7 +519,92 @@ 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 + Vio *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 specified attrib */ + /* + 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); + } + break; + } +#else /* HAVE_OPENSSL */ user_access=acl_user->access; +#endif /* HAVE_OPENSSL */ + *mqh=acl_user->user_resource; if (!acl_user->user) *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */ break; @@ -457,7 +633,13 @@ 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, + enum SSL_type ssl_type, + const char *ssl_cipher, + const char *x509_issuer, + const char *x509_subject, + USER_RESOURCES *mqh, + ulong privileges) { for (uint i=0 ; i < acl_users.elements ; i++) { @@ -470,6 +652,18 @@ 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; + if (mqh->bits & 1) + acl_user->user_resource.questions=mqh->questions; + if (mqh->bits & 2) + acl_user->user_resource.updates=mqh->updates; + if (mqh->bits & 4) + acl_user->user_resource.connections=mqh->connections; +#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]) @@ -488,16 +682,28 @@ 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, - uint privileges) + const char *password, + enum SSL_type ssl_type, + const char *ssl_cipher, + const char *x509_issuer, + const char *x509_subject, + USER_RESOURCES *mqh, + ulong privileges) { ACL_USER acl_user; acl_user.user=strdup_root(&mem,user); update_hostname(&acl_user.host,strdup_root(&mem,host)); acl_user.password=0; acl_user.access=privileges; + acl_user.user_resource = *mqh; 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 @@ -519,7 +725,7 @@ static void acl_insert_user(const char *user, const char *host, static void acl_update_db(const char *user, const char *host, const char *db, - uint privileges) + ulong privileges) { for (uint i=0 ; i < acl_dbs.elements ; i++) { @@ -546,7 +752,7 @@ static void acl_update_db(const char *user, const char *host, const char *db, static void acl_insert_db(const char *user, const char *host, const char *db, - uint privileges) + ulong privileges) { ACL_DB acl_db; /* The acl_cache mutex is locked by mysql_grant */ @@ -565,17 +771,24 @@ static void acl_insert_db(const char *user, const char *host, const char *db, ** Get privilege for a host, user and db combination *****************************************************************************/ -uint acl_get(const char *host, const char *ip, const char *bin_ip, +ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db) { - uint host_access,db_access,i,key_length; + ulong host_access,db_access; + uint i,key_length; db_access=0; host_access= ~0; - char key[ACL_KEY_LENGTH],*end; + char key[ACL_KEY_LENGTH],*tmp_db,*end; acl_entry *entry; + THD *thd= current_thd; VOID(pthread_mutex_lock(&acl_cache->lock)); memcpy_fixed(&key,bin_ip,sizeof(struct in_addr)); - end=strmov(strmov(key+sizeof(struct in_addr),user)+1,db); + end=strmov((tmp_db=strmov(key+sizeof(struct in_addr),user)+1),db); + if (lower_case_table_names) + { + casedn_str(tmp_db); + db=tmp_db; + } key_length=(uint) (end-key); if ((entry=(acl_entry*) acl_cache->search(key,key_length))) { @@ -641,7 +854,7 @@ int wild_case_compare(const char *str,const char *wildstr) { reg3 int flag; DBUG_ENTER("wild_case_compare"); - + DBUG_PRINT("enter",("str: '%s' wildstr: '%s'",str,wildstr)); while (*wildstr) { while (*wildstr && *wildstr != wild_many && *wildstr != wild_one) @@ -653,7 +866,7 @@ int wild_case_compare(const char *str,const char *wildstr) if (! *wildstr ) DBUG_RETURN (*str != 0); if (*wildstr++ == wild_one) { - if (! *str++) DBUG_RETURN (1); /* One char; skipp */ + if (! *str++) DBUG_RETURN (1); /* One char; skip */ } else { /* Found '*' */ @@ -757,44 +970,70 @@ bool acl_check_host(const char *host, const char *ip) } /***************************************************************************** -** Change password for the user if it's not an anonymous user -** Note: This should write the error directly to the client! + Change password for the user if it's not an anonymous user + Note: This should write the error directly to the client! *****************************************************************************/ -bool change_password(THD *thd, const char *host, const char *user, - char *new_password) +/* + Check if the user is allowed to change password + + SYNOPSIS: + check_change_password() + thd THD + host hostname for the user + user user name + + RETURN VALUE + 0 OK + 1 ERROR ; In this case the error is sent to the client. +*/ + +bool check_change_password(THD *thd, const char *host, const char *user) { - uint length=0; if (!initialized) { send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */ - return 1; /* purecov: inspected */ + return(1); /* purecov: inspected */ } - if (!host) - host=thd->ip; /* purecov: tested */ - /* password should always be 0 or 16 chars; simple hack to avoid cracking */ - length=(uint) strlen(new_password); - new_password[length & 16]=0; - if (!thd->slave_thread && (strcmp(thd->user,user) || my_strcasecmp(host,thd->host ? thd->host : thd->ip))) { if (check_access(thd, UPDATE_ACL, "mysql",0,1)) - return 1; + return(1); } if (!thd->slave_thread && !thd->user[0]) { send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER); - return 1; + return(1); } + return(0); +} + + +bool change_password(THD *thd, const char *host, const char *user, + char *new_password) +{ + uint length=0; + DBUG_ENTER("change_password"); + DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", + host,user,new_password)); + DBUG_ASSERT(host != 0); // Ensured by parent + + if (check_change_password(thd, host, user)) + DBUG_RETURN(1); + + /* password should always be 0 or 16 chars; simple hack to avoid cracking */ + length=(uint) strlen(new_password); + new_password[length & 16]=0; + VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; if (!(acl_user= find_acl_user(host,user))) { send_error(&thd->net, ER_PASSWORD_NO_MATCH); VOID(pthread_mutex_unlock(&acl_cache->lock)); - return 1; + DBUG_RETURN(1); } if (update_user_table(thd, acl_user->host.hostname ? acl_user->host.hostname : "", @@ -803,7 +1042,7 @@ bool change_password(THD *thd, const char *host, const char *user, { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ send_error(&thd->net,0); /* purecov: deadcode */ - return 1; /* purecov: deadcode */ + DBUG_RETURN(1); /* purecov: deadcode */ } get_salt_from_password(acl_user->salt,new_password); if (!new_password[0]) @@ -814,7 +1053,7 @@ bool change_password(THD *thd, const char *host, const char *user, VOID(pthread_mutex_unlock(&acl_cache->lock)); char buff[460]; - + Query_log_event qinfo(thd, buff); qinfo.q_len = my_sprintf(buff, @@ -824,7 +1063,7 @@ bool change_password(THD *thd, const char *host, const char *user, new_password)); mysql_update_log.write(thd,buff,qinfo.q_len); mysql_bin_log.write(&qinfo); - return 0; + DBUG_RETURN(0); } @@ -835,17 +1074,23 @@ bool change_password(THD *thd, const char *host, const char *user, static ACL_USER * find_acl_user(const char *host, const char *user) { + DBUG_ENTER("find_acl_user"); + DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user)); for (uint i=0 ; i < acl_users.elements ; i++) { ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); + DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),", + user,acl_user->user,(host),(acl_user->host))); if (!acl_user->user && !user[0] || acl_user->user && !strcmp(user,acl_user->user)) { - if (compare_hostname(&acl_user->host,host,host)) - return acl_user; + if (compare_hostname(&(acl_user->host),host,host)) + { + DBUG_RETURN(acl_user); + } } } - return 0; + DBUG_RETURN(0); } /***************************************************************************** @@ -904,7 +1149,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, /**************************************************************************** -** Code to update grants in the user and database privilege tables + Code to update grants in the user and database privilege tables ****************************************************************************/ static bool update_user_table(THD *thd, const char *host, const char *user, @@ -954,10 +1199,10 @@ static bool test_if_create_new_users(THD *thd) if (opt_safe_user_create && !(thd->master_access & INSERT_ACL)) { TABLE_LIST tl; - uint db_access; + ulong db_access; bzero((char*) &tl,sizeof(tl)); tl.db= (char*) "mysql"; - tl.real_name= (char*) "user"; + tl.real_name= (char*) "user"; db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr, thd->priv_user, tl.db); if (!(db_access & INSERT_ACL)) @@ -974,13 +1219,14 @@ static bool test_if_create_new_users(THD *thd) ** Handle GRANT commands ****************************************************************************/ -static int replace_user_table(TABLE *table, const LEX_USER &combo, - uint rights, char what, bool create_user) +static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, + ulong rights, bool revoke_grant, + bool create_user) { int error = -1; - uint i,j; bool old_row_exists=0; char *password,empty_string[1]; + char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_user_table"); password=empty_string; @@ -1013,7 +1259,7 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo, my_printf_error(ER_NO_PERMISSION_TO_CREATE_USER, ER(ER_NO_PERMISSION_TO_CREATE_USER), MYF(0),thd->user, - thd->host ? thd->host : thd->ip ? thd->ip: ""); + thd->host_or_ip); error= -1; goto end; } @@ -1031,15 +1277,60 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo, table->field[2]->store(password,(uint) strlen(password)); } - for (i = 3, j = SELECT_ACL; // starting from reload - i < table->fields; - i++, j <<= 1) + /* Update table columns with new privileges */ + + Field **tmp_field; + ulong priv; + for (tmp_field= table->field+3, priv = SELECT_ACL; + *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM && + ((Field_enum*) (*tmp_field))->typelib->count == 2 ; + tmp_field++, priv <<= 1) { - if (j & rights) // set requested privileges - table->field[i]->store(&what,1); + if (priv & rights) // set requested privileges + (*tmp_field)->store(&what,1); } rights=get_access(table,3); + DBUG_PRINT("info",("table->fields: %d",table->fields)); + if (table->fields >= 31) /* From 4.0.0 we have more fields */ + { +#ifdef HAVE_OPENSSL + /* We write down SSL related ACL stuff */ + table->field[25]->store("",0); + table->field[26]->store("",0); + table->field[27]->store("",0); + switch (thd->lex.ssl_type) { + case SSL_TYPE_ANY: + table->field[24]->store("ANY",3); + break; + case SSL_TYPE_X509: + table->field[24]->store("X509",4); + break; + case SSL_TYPE_SPECIFIED: + table->field[24]->store("SPECIFIED",9); + if (thd->lex.ssl_cipher) + table->field[25]->store(thd->lex.ssl_cipher, + strlen(thd->lex.ssl_cipher)); + if (thd->lex.x509_issuer) + table->field[26]->store(thd->lex.x509_issuer, + strlen(thd->lex.x509_issuer)); + if (thd->lex.x509_subject) + table->field[27]->store(thd->lex.x509_subject, + strlen(thd->lex.x509_subject)); + break; + default: + table->field[24]->store("",0); + } +#endif /* HAVE_OPENSSL */ + USER_RESOURCES mqh = thd->lex.mqh; + if (mqh.bits & 1) + table->field[28]->store((longlong) mqh.questions); + if (mqh.bits & 2) + table->field[29]->store((longlong) mqh.updates); + if (mqh.bits & 4) + table->field[30]->store((longlong) mqh.connections); + mqh_used = mqh_used || mqh.questions || mqh.updates || mqh.connections; + } if (old_row_exists) { /* @@ -1066,16 +1357,28 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo, } error=0; // Privileges granted / revoked - end: +end: if (!error) { acl_cache->clear(1); // Clear privilege cache 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, + thd->lex.ssl_type, + thd->lex.ssl_cipher, + thd->lex.x509_issuer, + thd->lex.x509_subject, + &thd->lex.mqh, + rights); else - acl_insert_user(combo.user.str,combo.host.str,password,rights); + acl_insert_user(combo.user.str,combo.host.str,password, + thd->lex.ssl_type, + thd->lex.ssl_cipher, + thd->lex.x509_issuer, + thd->lex.x509_subject, + &thd->lex.mqh, + rights); } table->file->index_end(); DBUG_RETURN(error); @@ -1083,16 +1386,18 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo, /* -** change grants in the mysql.db table + change grants in the mysql.db table */ static int replace_db_table(TABLE *table, const char *db, const LEX_USER &combo, - uint rights, char what) + ulong rights, bool revoke_grant) { - uint i,j,store_rights; + uint i; + ulong priv,store_rights; bool old_row_exists=0; int error; + char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_db_table"); // is there such a user in user table in memory ???? @@ -1128,9 +1433,9 @@ static int replace_db_table(TABLE *table, const char *db, } store_rights=get_rights_for_db(rights); - for (i = 3, j = 1; i < table->fields; i++, j <<= 1) + for (i= 3, priv= 1; i < table->fields; i++, priv <<= 1) { - if (j & store_rights) // do it if priv is chosen + if (priv & store_rights) // do it if priv is chosen table->field [i]->store(&what,1); // set requested privileges } rights=get_access(table,3); @@ -1178,13 +1483,15 @@ class GRANT_COLUMN :public Sql_alloc { public: char *column; - uint rights, key_length; - GRANT_COLUMN(String &c, uint y) :rights (y) + ulong rights; + uint key_length; + GRANT_COLUMN(String &c, ulong y) :rights (y) { - column= memdup_root(&memex,c.ptr(),key_length=c.length()); + column= memdup_root(&memex,c.ptr(), key_length=c.length()); } }; + static byte* get_key_column(GRANT_COLUMN *buff,uint *length, my_bool not_used __attribute__((unused))) { @@ -1192,20 +1499,27 @@ static byte* get_key_column(GRANT_COLUMN *buff,uint *length, return (byte*) buff->column; } + class GRANT_TABLE :public Sql_alloc { public: char *host,*db,*user,*tname, *hash_key; - uint privs, cols, key_length; + ulong privs, cols; + uint key_length; HASH hash_columns; GRANT_TABLE (const char *h, const char *d,const char *u, const char *t, - uint p,uint c) + ulong p, ulong c) : privs(p), cols(c) { host = strdup_root(&memex,h); db = strdup_root(&memex,d); user = strdup_root(&memex,u); tname= strdup_root(&memex,t); + if (lower_case_table_names) + { + casedn_str(db); + casedn_str(tname); + } key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3; hash_key = (char*) alloc_root(&memex,key_length); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); @@ -1219,7 +1533,9 @@ public: host = get_field(&memex,form,0); db = get_field(&memex,form,1); - user = get_field(&memex,form,2); if (!user) user=(char*) ""; + user = get_field(&memex,form,2); + if (!user) + user=(char*) ""; tname = get_field(&memex,form,3); if (!host || !db || !tname) { @@ -1227,11 +1543,17 @@ public: privs = cols = 0; /* purecov: inspected */ return; /* purecov: inspected */ } - key_length = (uint) strlen(db) + (uint) strlen(user) + (uint) strlen (tname) + 3; + if (lower_case_table_names) + { + casedn_str(db); + casedn_str(tname); + } + key_length = ((uint) strlen(db) + (uint) strlen(user) + + (uint) strlen(tname) + 3); hash_key = (char*) alloc_root(&memex,key_length); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); - privs = (uint) form->field[6]->val_int(); - cols = (uint) form->field[7]->val_int(); + privs = (ulong) form->field[6]->val_int(); + cols = (ulong) form->field[7]->val_int(); privs = fix_rights_for_table(privs); cols = fix_rights_for_column(cols); @@ -1264,7 +1586,7 @@ public: GRANT_COLUMN *mem_check; /* As column name is a string, we don't have to supply a buffer */ res=col_privs->field[4]->val_str(&column_name,&column_name); - uint priv= (uint) col_privs->field[6]->val_int(); + ulong priv= (ulong) col_privs->field[6]->val_int(); if (!(mem_check = new GRANT_COLUMN(*res, fix_rights_for_column(priv)))) { @@ -1280,6 +1602,7 @@ public: bool ok() { return privs != 0 || cols != 0; } }; + static byte* get_grant_table(GRANT_TABLE *buff,uint *length, my_bool not_used __attribute__((unused))) { @@ -1287,11 +1610,13 @@ static byte* get_grant_table(GRANT_TABLE *buff,uint *length, return (byte*) buff->hash_key; } + void free_grant_table(GRANT_TABLE *grant_table) { hash_free(&grant_table->hash_columns); } + /* Search after a matching grant. Prefer exact grants before not exact ones */ static GRANT_TABLE *table_hash_search(const char *host,const char* ip, @@ -1328,8 +1653,7 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip, inline GRANT_COLUMN * -column_hash_search(GRANT_TABLE *t, const char *cname, - uint length) +column_hash_search(GRANT_TABLE *t, const char *cname, uint length) { return (GRANT_COLUMN*) hash_search(&t->hash_columns, (byte*) cname,length); } @@ -1339,7 +1663,7 @@ static int replace_column_table(GRANT_TABLE *g_t, TABLE *table, const LEX_USER &combo, List <LEX_COLUMN> &columns, const char *db, const char *table_name, - uint rights, bool revoke_grant) + ulong rights, bool revoke_grant) { int error=0,result=0; uint key_length; @@ -1363,7 +1687,7 @@ static int replace_column_table(GRANT_TABLE *g_t, table->file->index_init(0); while ((xx=iter++)) { - uint privileges = xx->rights; + ulong privileges = xx->rights; bool old_row_exists=0; key_restore(table,key,0,key_length); table->field[4]->store(xx->column.ptr(),xx->column.length()); @@ -1386,7 +1710,7 @@ static int replace_column_table(GRANT_TABLE *g_t, } else { - uint tmp= (uint) table->field[6]->val_int(); + ulong tmp= (ulong) table->field[6]->val_int(); tmp=fix_rights_for_column(tmp); if (revoke_grant) @@ -1446,7 +1770,7 @@ static int replace_column_table(GRANT_TABLE *g_t, // Scan trough all rows with the same host,db,user and table do { - uint privileges = (uint) table->field[6]->val_int(); + ulong privileges = (ulong) table->field[6]->val_int(); privileges=fix_rights_for_column(privileges); store_record(table,1); @@ -1502,19 +1826,21 @@ static int replace_column_table(GRANT_TABLE *g_t, static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, TABLE *table, const LEX_USER &combo, const char *db, const char *table_name, - uint rights, uint kolone, bool revoke_grant) + ulong rights, ulong col_rights, + bool revoke_grant) { char grantor[HOSTNAME_LENGTH+1+USERNAME_LENGTH]; int old_row_exists = 1; int error=0; - uint store_table_rights,store_col_rights; + ulong store_table_rights, store_col_rights; DBUG_ENTER("replace_table_table"); - strxmov(grantor,thd->user,"@",thd->host ? thd->host : thd->ip ? thd->ip :"", - NullS); + strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); - // The following should always succeed as new users are created before - // this function is called! + /* + The following should always succeed as new users are created before + this function is called! + */ if (!find_acl_user(combo.host.str,combo.user.str)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */ @@ -1549,14 +1875,14 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, restore_record(table,1); // Get saved record } - store_table_rights=get_rights_for_table(rights); - store_col_rights=get_rights_for_column(kolone); + store_table_rights= get_rights_for_table(rights); + store_col_rights= get_rights_for_column(col_rights); if (old_row_exists) { - uint j,k; + ulong j,k; store_record(table,1); - j = (uint) table->field[6]->val_int(); - k = (uint) table->field[7]->val_int(); + j = (ulong) table->field[6]->val_int(); + k = (ulong) table->field[7]->val_int(); if (revoke_grant) { @@ -1565,8 +1891,8 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } else { - store_table_rights|=j; - store_col_rights|=k; + store_table_rights|= j; + store_col_rights|= k; } } @@ -1574,7 +1900,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, table->field[6]->store((longlong) store_table_rights); table->field[7]->store((longlong) store_col_rights); rights=fix_rights_for_table(store_table_rights); - kolone=fix_rights_for_column(store_col_rights); + col_rights=fix_rights_for_column(store_col_rights); if (old_row_exists) { @@ -1593,10 +1919,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, goto table_error; /* purecov: deadcode */ } - if (rights | kolone) + if (rights | col_rights) { - grant_table->privs = rights; - grant_table->cols = kolone; + grant_table->privs= rights; + grant_table->cols= col_rights; } else { @@ -1613,10 +1939,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, int mysql_table_grant (THD *thd, TABLE_LIST *table_list, List <LEX_USER> &user_list, - List <LEX_COLUMN> &columns, uint rights, + List <LEX_COLUMN> &columns, ulong rights, bool revoke_grant) { - uint column_priv = 0; + ulong column_priv = 0; List_iterator <LEX_USER> str_list (user_list); LEX_USER *Str; TABLE_LIST tables[3]; @@ -1711,11 +2037,8 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, continue; } /* Create user if needed */ - if (replace_user_table(tables[0].table, - *Str, - 0, - revoke_grant ? 'N' : 'Y', - create_new_users)) + if (replace_user_table(thd, tables[0].table, *Str, + 0, revoke_grant, create_new_users)) { result= -1; // Remember error continue; // Add next user @@ -1806,17 +2129,17 @@ 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); } -int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights, - bool revoke_grant) +int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, + ulong rights, bool revoke_grant) { List_iterator <LEX_USER> str_list (list); LEX_USER *Str; - char what; + char tmp_db[NAME_LEN+1]; bool create_new_users=0; TABLE_LIST tables[2]; DBUG_ENTER("mysql_grant"); @@ -1827,7 +2150,12 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights, return 1; /* purecov: tested */ } - what = (revoke_grant) ? 'N' : 'Y'; + if (lower_case_table_names && db) + { + strmov(tmp_db,db); + casedn_str(tmp_db); + db=tmp_db; + } /* open the mysql.user and mysql.db tables */ @@ -1867,14 +2195,16 @@ 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))) + (!db ? rights : 0), revoke_grant, + create_new_users))) result= -1; else { if (db && replace_db_table(tables[1].table, db, *Str, rights & DB_ACLS, - what)) + revoke_grant)) result= -1; } } @@ -1887,7 +2217,8 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights, DBUG_RETURN(result); } - /* Free grant array if possible */ + +/* Free grant array if possible */ void grant_free(void) { @@ -1923,7 +2254,8 @@ int grant_init (void) thd->mysys_var=my_thread_var; thd->current_tablenr=0; thd->open_tables=0; - thd->db=my_strdup("mysql",MYF(0)); + thd->db= my_strdup("mysql",MYF(0)); + thd->db_length=5; // Safety bzero((char*) &tables,sizeof(tables)); tables[0].name=tables[0].real_name= (char*) "tables_priv"; tables[1].name=tables[1].real_name= (char*) "columns_priv"; @@ -1959,7 +2291,7 @@ int grant_init (void) delete thd; DBUG_RETURN(0); // Empty table is ok! } - grant_option = TRUE; + grant_option= TRUE; t_table->file->index_end(); MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); @@ -2023,11 +2355,11 @@ void grant_reload(void) /**************************************************************************** -** Check grants -** All errors are written directly to the client if command name is given ! + Check grants + All errors are written directly to the client if command name is given ! ****************************************************************************/ -bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, +bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, uint show_table, bool no_errors) { TABLE_LIST *table; @@ -2045,8 +2377,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, table->grant.want_privilege=0; continue; // Already checked } - const char *db = table->db ? table->db : thd->db; - GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,db,user, + GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip, + table->db,user, table->real_name,0); if (!grant_table) { @@ -2100,7 +2432,7 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR, command, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, table ? table->real_name : "unknown"); } return 1; @@ -2113,7 +2445,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; - uint want_access=table->grant.want_privilege; + ulong want_access=table->grant.want_privilege; if (!want_access) return 0; // Already checked @@ -2151,19 +2483,14 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, pthread_mutex_unlock(&LOCK_grant); if (!show_tables) { - const char *command=""; - if (want_access & SELECT_ACL) - command ="select"; - else if (want_access & INSERT_ACL) - command = "insert"; - else if (want_access & UPDATE_ACL) - command = "update"; + char command[128]; + get_privilege_desc(command, sizeof(command), want_access); my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, ER(ER_COLUMNACCESS_DENIED_ERROR), MYF(0), command, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, name, table ? table->real_name : "unknown"); } @@ -2171,7 +2498,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, } -bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table) +bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) { GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; @@ -2221,7 +2548,7 @@ bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table) MYF(0), command, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, field ? field->field_name : "unknown", table->real_name); return 1; @@ -2229,9 +2556,9 @@ bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table) /**************************************************************************** -** Check if a user has the right to access a database -** Access is accepted if he has a grant for any table in the database -** Return 1 if access is denied + Check if a user has the right to access a database + Access is accepted if he has a grant for any table in the database + Return 1 if access is denied ****************************************************************************/ bool check_grant_db(THD *thd,const char *db) @@ -2260,10 +2587,10 @@ bool check_grant_db(THD *thd,const char *db) } /***************************************************************************** -** Functions to retrieve the grant for a table/column (for SHOW functions) + Functions to retrieve the grant for a table/column (for SHOW functions) *****************************************************************************/ -uint get_table_grant(THD *thd, TABLE_LIST *table) +ulong get_table_grant(THD *thd, TABLE_LIST *table) { char *user = thd->priv_user; const char *db = table->db ? table->db : thd->db; @@ -2281,11 +2608,11 @@ uint get_table_grant(THD *thd, TABLE_LIST *table) } -uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field) +ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) { GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; - uint priv; + ulong priv; pthread_mutex_lock(&LOCK_grant); // reload table if someone has modified any grants @@ -2315,22 +2642,31 @@ uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field) /***************************************************************************** -** SHOW GRANTS : send to client grant-like strings depicting user@host -** privileges + SHOW GRANTS : send to client grant-like strings depicting user@host + privileges *****************************************************************************/ static const char *command_array[]= -{"SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP","RELOAD","SHUTDOWN", - "PROCESS","FILE","GRANT","REFERENCES","INDEX","ALTER"}; -static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,10,5,5}; +{ + "SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP", "RELOAD","SHUTDOWN", + "PROCESS","FILE","GRANT","REFERENCES","INDEX", "ALTER", "SHOW DATABASES", + "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", + "REPLICATION SLAVE", "REPLICATION CLIENT", +}; +static uint command_lengths[]= +{ + 6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18 +}; + int mysql_show_grants(THD *thd,LEX_USER *lex_user) { - uint counter, want_access,index; + ulong want_access; + uint counter,index; int error = 0; ACL_USER *acl_user; ACL_DB *acl_db; char buff[1024]; - DBUG_ENTER("mysql_grant"); + DBUG_ENTER("mysql_show_grants"); LINT_INIT(acl_user); if (!initialized) @@ -2396,7 +2732,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) else { bool found=0; - uint j,test_access= want_access & ~GRANT_ACL; + ulong j,test_access= want_access & ~GRANT_ACL; for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1) { if (test_access & j) @@ -2421,8 +2757,70 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(passd_buff); global.append('\''); } - if (want_access & GRANT_ACL) - global.append(" WITH GRANT OPTION",18); +#ifdef HAVE_OPENSSL + /* "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) + { + int ssl_options = 0; + global.append(" REQUIRE ",9); + if (acl_user->x509_issuer) + { + ssl_options++; + global.append("ISSUER \"",8); + global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + global.append('\''); + } + 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('\''); + } + 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('\''); + } + } +#endif /* HAVE_OPENSSL */ + if ((want_access & GRANT_ACL) || + (acl_user->user_resource.questions | acl_user->user_resource.updates | + acl_user->user_resource.connections)) + { + global.append(" WITH",5); + if (want_access & GRANT_ACL) + global.append(" GRANT OPTION",13); + if (acl_user->user_resource.questions) + { + char buff[22], *p; // just as in int2str + global.append(" MAX_QUERIES_PER_HOUR ",22); + p=int10_to_str(acl_user->user_resource.questions,buff,10); + global.append(buff,p-buff); + } + if (acl_user->user_resource.updates) + { + char buff[22], *p; // just as in int2str + global.append(" MAX_UPDATES_PER_HOUR ",22); + p=int10_to_str(acl_user->user_resource.updates,buff,10); + global.append(buff,p-buff); + } + if (acl_user->user_resource.connections) + { + char buff[22], *p; // just as in int2str + global.append(" MAX_CONNECTIONS_PER_HOUR ",26); + p=int10_to_str(acl_user->user_resource.connections,buff,10); + global.append(buff,p-buff); + } + } thd->packet.length(0); net_store_data(&thd->packet,global.ptr(),global.length()); if (my_net_write(&thd->net,(char*) thd->packet.ptr(), @@ -2458,7 +2856,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) else { int found=0, cnt; - uint j,test_access= want_access & ~GRANT_ACL; + ulong j,test_access= want_access & ~GRANT_ACL; for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1) { if (test_access & j) @@ -2478,7 +2876,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) db.append(lex_user->host.str, lex_user->host.length); db.append ('\''); if (want_access & GRANT_ACL) - db.append(" WITH GRANT OPTION",18); + db.append(" WITH GRANT OPTION",18); thd->packet.length(0); net_store_data(&thd->packet,db.ptr(),db.length()); if (my_net_write(&thd->net,(char*) thd->packet.ptr(), @@ -2517,7 +2915,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) else { int found=0; - uint j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL; + ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL; for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1) { @@ -2585,8 +2983,47 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } +/* + Make a clear-text version of the requested privilege. +*/ + +void get_privilege_desc(char *to, uint max_length, ulong access) +{ + uint pos; + char *start=to; + DBUG_ASSERT(max_length >= 30); // For end ',' removal + + if (access) + { + max_length--; // Reserve place for end-zero + for (pos=0 ; access ; pos++, access>>=1) + { + if ((access & 1) && + command_lengths[pos] + (uint) (to-start) < max_length) + { + to= strmov(to, command_array[pos]); + *to++=','; + } + } + to--; // Remove end ',' + } + *to=0; +} + + +void get_mqh(const char *user, const char *host, USER_CONN *uc) +{ + ACL_USER *acl_user; + if (initialized && (acl_user= find_acl_user(host,user))) + uc->user_resources= acl_user->user_resource; + else + bzero((char*) &uc->user_resources, sizeof(uc->user_resources)); +} + + + /***************************************************************************** -** Instantiate used templates + Instantiate used templates *****************************************************************************/ #ifdef __GNUC__ |