1 /* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License, version 2.0, 5 as published by the Free Software Foundation. 6 7 This program is also distributed with certain software (including 8 but not limited to OpenSSL) that is licensed under separate terms, 9 as designated in a particular file or component or in included license 10 documentation. The authors of MySQL hereby grant you an additional 11 permission to link the program and your derivative works with the 12 separately licensed software that they have included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 22 23 #include "security_context_imp.h" 24 25 #include <mysql/components/minimal_chassis.h> 26 #include "sql/auth/auth_acls.h" 27 #include "sql/current_thd.h" 28 #include "sql/sql_class.h" 29 #include "sql/sql_thd_internal_api.h" // create_thd 30 31 /** 32 Gets the security context for the thread. 33 34 @param[in] _thd The thread to get the context from 35 @param[out] out_ctx placeholder for the security context handle 36 @retval true failure 37 @retval false success 38 */ 39 DEFINE_BOOL_METHOD(mysql_security_context_imp::get, 40 (void *_thd, Security_context_handle *out_ctx)) { 41 THD *thd = reinterpret_cast<THD *>(_thd); 42 43 if (!out_ctx) return true; 44 45 try { 46 *out_ctx = 47 reinterpret_cast<Security_context_handle>(thd->security_context()); 48 return false; 49 } catch (...) { 50 mysql_components_handle_std_exception(__func__); 51 } 52 return true; 53 } 54 55 /** 56 Sets a new security context for the thread. 57 58 @param[in] _thd The thread to set the context to 59 @param[in] in_ctx The handle of the new security context 60 @retval true failure 61 @retval false success 62 */ 63 DEFINE_BOOL_METHOD(mysql_security_context_imp::set, 64 (void *_thd, Security_context_handle in_ctx)) { 65 THD *thd = reinterpret_cast<THD *>(_thd); 66 67 if (!in_ctx) return true; 68 69 try { 70 Security_context *in_sctx = reinterpret_cast<Security_context *>(in_ctx); 71 if (in_sctx) { 72 thd->set_security_context(in_sctx); 73 in_sctx->set_thd(thd); 74 75 // Turn ON the flag in THD iff the user is granted SYSTEM_USER privilege 76 set_system_user_flag(thd); 77 } 78 return false; 79 } catch (...) { 80 mysql_components_handle_std_exception(__func__); 81 } 82 return true; 83 } 84 85 /** 86 Creates a new security context and initializes it with the defaults 87 (no access, no user etc). 88 89 @param[out] out_ctx placeholder for the newly created security context 90 handle 91 @retval true failure 92 @retval false success 93 */ 94 DEFINE_BOOL_METHOD(mysql_security_context_imp::create, 95 (Security_context_handle * out_ctx)) { 96 try { 97 *out_ctx = 98 reinterpret_cast<Security_context_handle>(new Security_context()); 99 return false; 100 } catch (...) { 101 mysql_components_handle_std_exception(__func__); 102 } 103 return true; 104 } 105 106 /** 107 Deallocates a security context. 108 109 @param[in] ctx The handle of the security context to destroy 110 @retval true failure 111 @retval false success 112 */ 113 DEFINE_BOOL_METHOD(mysql_security_context_imp::destroy, 114 (Security_context_handle ctx)) { 115 try { 116 delete reinterpret_cast<Security_context *>(ctx); 117 return false; 118 } catch (...) { 119 mysql_components_handle_std_exception(__func__); 120 } 121 return true; 122 } 123 124 /** 125 Duplicates a security context. 126 127 @param[in] in_ctx The handle of the security context to copy 128 @param[out] out_ctx placeholder for the handle of the copied 129 security context 130 @retval true failure 131 @retval false success 132 */ 133 DEFINE_BOOL_METHOD(mysql_security_context_imp::copy, 134 (Security_context_handle in_ctx, 135 Security_context_handle *out_ctx)) { 136 try { 137 if (out_ctx) { 138 *out_ctx = 139 reinterpret_cast<Security_context_handle>(new Security_context()); 140 if (in_ctx && *out_ctx) 141 *out_ctx = reinterpret_cast<Security_context_handle>(in_ctx); 142 else 143 return true; 144 return false; 145 } 146 } catch (...) { 147 mysql_components_handle_std_exception(__func__); 148 } 149 return true; 150 } 151 152 /** 153 Looks up in the defined user accounts an account based on 154 the user\@host[ip] combo supplied and checks if the user 155 has access to the database requested. 156 The lookup is done in exactly the same way as at login time. 157 The new security context need to checkout additional privileges using 158 the checkout_acl method. 159 @param[in] ctx The handle of the security context to update 160 @param[in] user The user name to look up, the name has to be in utf8 charset 161 @param[in] host The host name to look up, the name has to be in utf8 charset 162 @param[in] ip The ip of the incoming connection 163 @param[in] db The database to check access to 164 @retval true failure 165 @retval false success 166 */ 167 DEFINE_BOOL_METHOD(mysql_security_context_imp::lookup, 168 (Security_context_handle ctx, const char *user, 169 const char *host, const char *ip, const char *db)) { 170 try { 171 THD *tmp_thd = nullptr; 172 bool retval; 173 if (current_thd == nullptr) { 174 tmp_thd = create_thd(false, true, false, PSI_NOT_INSTRUMENTED); 175 if (!tmp_thd) return true; 176 } 177 178 retval = acl_getroot(tmp_thd ? tmp_thd : current_thd, 179 reinterpret_cast<Security_context *>(ctx), user, host, 180 ip, db) 181 ? true 182 : false; 183 184 /* 185 If it is not a new security context then update the 186 system_user flag in its referenced THD. 187 */ 188 Security_context *sctx = reinterpret_cast<Security_context *>(ctx); 189 THD *sctx_thd = sctx->get_thd(); 190 if (sctx_thd) set_system_user_flag(sctx_thd); 191 192 if (tmp_thd) { 193 destroy_thd(tmp_thd); 194 tmp_thd = nullptr; 195 } 196 return retval; 197 } catch (...) { 198 mysql_components_handle_std_exception(__func__); 199 } 200 return true; 201 } 202 203 /** 204 Reads a named security context attribute and retuns its value. 205 Currently defined names are: 206 207 - user MYSQL_LEX_CSTRING * login user (a.k.a. the user's part of USER()) 208 - host MYSQL_LEX_CSTRING * login host (a.k.a. the host's part of USER()) 209 - ip MYSQL_LEX_CSTRING * login client ip 210 - host_or_ip MYSQL_LEX_CSTRING * host, if present, ip if not. 211 - priv_user MYSQL_LEX_CSTRING * authenticated user 212 (a.k.a. the user's part of CURRENT_USER()) 213 - priv_host MYSQL_LEX_CSTRING * authenticated host 214 (a.k.a. the host's part of CURRENT_USER()) 215 - proxy_user MYSQL_LEX_CSTRING * the proxy user used in authenticating 216 217 - privilege_super DECLARE_BOOL_METHOD * 1 if the user account has 218 supper privilege, 0 otherwise 219 - privilege_execute DECLARE_BOOL_METHOD * 1 if the user account has 220 execute privilege, 0 otherwise 221 222 @param[in] ctx_h The handle of the security context to read from 223 @param[in] name The option name to read 224 @param[out] inout_pvalue The value of the option. Type depends on the name. 225 @retval true failure 226 @retval false success 227 */ 228 DEFINE_BOOL_METHOD(mysql_security_context_imp::get, 229 (Security_context_handle ctx_h, const char *name, 230 void *inout_pvalue)) { 231 try { 232 Security_context *ctx = reinterpret_cast<Security_context *>(ctx_h); 233 if (inout_pvalue) { 234 if (!strcmp(name, "user")) { 235 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->user(); 236 } else if (!strcmp(name, "host")) { 237 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->host(); 238 } else if (!strcmp(name, "ip")) { 239 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->ip(); 240 } else if (!strcmp(name, "host_or_ip")) { 241 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->host_or_ip(); 242 } else if (!strcmp(name, "priv_user")) { 243 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->priv_user(); 244 } else if (!strcmp(name, "priv_host")) { 245 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->priv_host(); 246 } else if (!strcmp(name, "proxy_user")) { 247 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->proxy_user(); 248 } else if (!strcmp(name, "external_user")) { 249 *((MYSQL_LEX_CSTRING *)inout_pvalue) = ctx->external_user(); 250 } else if (!strcmp(name, "privilege_super")) { 251 bool checked = ctx->check_access(SUPER_ACL); 252 *((bool *)inout_pvalue) = checked ? true : false; 253 } else if (!strcmp(name, "privilege_execute")) { 254 bool checked = ctx->check_access(EXECUTE_ACL); 255 *((bool *)inout_pvalue) = checked ? true : false; 256 } else 257 return true; /* invalid option */ 258 } 259 return false; 260 } catch (...) { 261 mysql_components_handle_std_exception(__func__); 262 } 263 return true; 264 } 265 266 /** 267 Sets a value for a named security context attribute 268 Currently defined names are: 269 270 - user MYSQL_LEX_CSTRING * login user (a.k.a. the user's part of USER()) 271 - host MYSQL_LEX_CSTRING * login host (a.k.a. the host's part of USER()) 272 - ip MYSQL_LEX_CSTRING * login client ip 273 - priv_user MYSQL_LEX_CSTRING * authenticated user 274 (a.k.a. the user's part of CURRENT_USER()) 275 - priv_host MYSQL_LEX_CSTRING * authenticated host 276 (a.k.a. the host's part of CURRENT_USER()) 277 - proxy_user MYSQL_LEX_CSTRING * the proxy user used in authenticating 278 279 - privilege_super DECLARE_BOOL_METHOD * 1 if the user account has 280 supper privilege, 0 otherwise 281 - privilege_execute DECLARE_BOOL_METHOD * 1 if the user account has 282 execute privilege, 0 otherwise 283 284 @param[in] ctx_h The handle of the security context to set into 285 @param[in] name The option name to set 286 @param[in] pvalue The value of the option. Type depends on the name. 287 @retval true failure 288 @retval false success 289 */ 290 DEFINE_BOOL_METHOD(mysql_security_context_imp::set, 291 (Security_context_handle ctx_h, const char *name, 292 void *pvalue)) { 293 try { 294 Security_context *ctx = reinterpret_cast<Security_context *>(ctx_h); 295 if (!strcmp(name, "user")) { 296 LEX_CSTRING *value = (LEX_CSTRING *)pvalue; 297 ctx->assign_user(value->str, value->length); 298 } else if (!strcmp(name, "host")) { 299 LEX_CSTRING *value = (LEX_CSTRING *)pvalue; 300 ctx->assign_host(value->str, value->length); 301 } else if (!strcmp(name, "ip")) { 302 LEX_CSTRING *value = (LEX_CSTRING *)pvalue; 303 ctx->assign_ip(value->str, value->length); 304 } else if (!strcmp(name, "priv_user")) { 305 LEX_CSTRING *value = (LEX_CSTRING *)pvalue; 306 ctx->assign_priv_user(value->str, value->length); 307 } else if (!strcmp(name, "priv_host")) { 308 LEX_CSTRING *value = (LEX_CSTRING *)pvalue; 309 ctx->assign_priv_host(value->str, value->length); 310 } else if (!strcmp(name, "proxy_user")) { 311 LEX_CSTRING *value = (LEX_CSTRING *)pvalue; 312 ctx->assign_proxy_user(value->str, value->length); 313 } else if (!strcmp(name, "privilege_super")) { 314 char value = *(char *)pvalue; 315 if (value) 316 ctx->set_master_access(ctx->master_access() | (SUPER_ACL), 317 ctx->restrictions()); 318 else 319 ctx->set_master_access(ctx->master_access() & ~(SUPER_ACL), 320 ctx->restrictions()); 321 } else if (!strcmp(name, "privilege_execute")) { 322 char value = *(char *)pvalue; 323 if (value) 324 ctx->set_master_access(ctx->master_access() | (EXECUTE_ACL), 325 ctx->restrictions()); 326 else 327 ctx->set_master_access(ctx->master_access() & ~(EXECUTE_ACL), 328 ctx->restrictions()); 329 } else 330 return true; /* invalid option */ 331 return false; 332 } catch (...) { 333 mysql_components_handle_std_exception(__func__); 334 } 335 return true; 336 } 337