bool set_pool(PgSocket *client, const char *dbname, const char *username, const char *password, bool takeover) { /* find database */ client->db = find_database(dbname); if (!client->db) { client->db = register_auto_database(dbname); if (!client->db) { disconnect_client(client, true, "No such database: %s", dbname); if (cf_log_connections) slog_info(client, "login failed: db=%s user=%s", dbname, username); return false; } else { slog_info(client, "registered new auto-database: db = %s", dbname ); } } /* are new connections allowed? */ if (client->db->db_disabled) { disconnect_client(client, true, "database does not allow connections: %s", dbname); return false; } if (client->db->admin) { if (admin_pre_login(client, username)) return finish_set_pool(client, takeover); } /* find user */ if (cf_auth_type == AUTH_ANY) { /* ignore requested user */ if (client->db->forced_user == NULL) { slog_error(client, "auth_type=any requires forced user"); disconnect_client(client, true, "bouncer config error"); return false; } client->auth_user = client->db->forced_user; } else { /* the user clients wants to log in as */ client->auth_user = find_user(username); if (!client->auth_user && client->db->auth_user) { if (takeover) { client->auth_user = add_db_user(client->db, username, password); return finish_set_pool(client, takeover); } start_auth_request(client, username); return false; } if (!client->auth_user) { disconnect_client(client, true, "No such user: %s", username); if (cf_log_connections) slog_info(client, "login failed: db=%s user=%s", dbname, username); return false; } } return finish_set_pool(client, takeover); }
bool set_pool(PgSocket *client, const char *dbname, const char *username) { PgDatabase *db; PgUser *user; /* find database */ db = find_database(dbname); if (!db) { db = register_auto_database(dbname); if (!db) { disconnect_client(client, true, "No such database: %s", dbname); return false; } else { slog_info(client, "registered new auto-database: db = %s", dbname ); } } /* are new connections allowed? */ if (db->db_disabled) { disconnect_client(client, true, "database does not allow connections: %s", dbname); return false; } /* find user */ if (cf_auth_type == AUTH_ANY) { /* ignore requested user */ user = NULL; if (db->forced_user == NULL) { slog_error(client, "auth_type=any requires forced user"); disconnect_client(client, true, "bouncer config error"); return false; } client->auth_user = db->forced_user; } else { /* the user clients wants to log in as */ user = find_user(username); if (!user) { disconnect_client(client, true, "No such user: %s", username); return false; } client->auth_user = user; } /* pool user may be forced */ if (db->forced_user) user = db->forced_user; client->pool = get_pool(db, user); if (!client->pool) { disconnect_client(client, true, "no memory for pool"); return false; } return check_fast_fail(client); }
/* decide on packets of logged-in client */ static bool handle_client_work(PgSocket *client, PktHdr *pkt) { SBuf *sbuf = &client->sbuf; switch (pkt->type) { /* one-packet queries */ case 'Q': /* Query */ if (cf_disable_pqexec) { slog_error(client, "Client used 'Q' packet type."); disconnect_client(client, true, "PQexec disallowed"); return false; } case 'F': /* FunctionCall */ /* request immediate response from server */ case 'H': /* Flush */ case 'S': /* Sync */ /* copy end markers */ case 'c': /* CopyDone(F/B) */ case 'f': /* CopyFail(F/B) */ /* * extended protocol allows server (and thus pooler) * to buffer packets until sync or flush is sent by client */ case 'P': /* Parse */ case 'E': /* Execute */ case 'C': /* Close */ case 'B': /* Bind */ case 'D': /* Describe */ case 'd': /* CopyData(F/B) */ /* update stats */ if (!client->query_start) { client->pool->stats.request_count++; client->query_start = get_cached_time(); } if (client->pool->db->admin) return admin_handle_client(client, pkt); /* aquire server */ if (!find_server(client)) return false; client->pool->stats.client_bytes += pkt->len; /* tag the server as dirty */ client->link->ready = false; client->link->idle_tx = false; /* forward the packet */ sbuf_prepare_send(sbuf, &client->link->sbuf, pkt->len); break; /* client wants to go away */ default: slog_error(client, "unknown pkt from client: %d/0x%x", pkt->type, pkt->type); disconnect_client(client, true, "unknown pkt"); return false; case 'X': /* Terminate */ disconnect_client(client, false, "client close request"); return false; } return true; }
bool set_pool(PgSocket *client, const char *dbname, const char *username, const char *password, bool takeover) { /* find database */ client->db = find_database(dbname); if (!client->db) { client->db = register_auto_database(dbname); if (!client->db) { disconnect_client(client, true, "no such database: %s", dbname); if (cf_log_connections) slog_info(client, "login failed: db=%s user=%s", dbname, username); return false; } else { slog_info(client, "registered new auto-database: db=%s", dbname); } } /* are new connections allowed? */ if (client->db->db_disabled) { disconnect_client(client, true, "database does not allow connections: %s", dbname); return false; } if (client->db->admin) { if (admin_pre_login(client, username)) return finish_set_pool(client, takeover); } /* find user */ if (cf_auth_type == AUTH_ANY) { /* ignore requested user */ if (client->db->forced_user == NULL) { slog_error(client, "auth_type=any requires forced user"); disconnect_client(client, true, "bouncer config error"); return false; } client->auth_user = client->db->forced_user; } else if (cf_auth_type == AUTH_PAM) { if (client->db->auth_user) { slog_error(client, "PAM can't be used together with database authorization"); disconnect_client(client, true, "bouncer config error"); return false; } /* Password will be set after successful authorization when not in takeover mode */ client->auth_user = add_pam_user(username, password); if (!client->auth_user) { slog_error(client, "set_pool(): failed to allocate new PAM user"); disconnect_client(client, true, "bouncer resources exhaustion"); return false; } } else { /* the user clients wants to log in as */ client->auth_user = find_user(username); if (!client->auth_user && client->db->auth_user) { if (takeover) { client->auth_user = add_db_user(client->db, username, password); return finish_set_pool(client, takeover); } start_auth_request(client, username); return false; } if (!client->auth_user) { disconnect_client(client, true, "no such user: %s", username); if (cf_log_connections) slog_info(client, "login failed: db=%s user=%s", dbname, username); return false; } } return finish_set_pool(client, takeover); }
char *pycall(PgSocket *client, char *username, char *query_str, char *py_file, char* py_function) { PyObject *pName = NULL, *pModule = NULL, *pFunc = NULL; PyObject *pArgs = NULL, *pValue = NULL; PyObject *ptype, *perror, *ptraceback; char *py_pathtmp, *py_filetmp, *py_path, *py_module, *ext; char *res = NULL; /* setup python search path */ py_pathtmp = malloc(strlen(py_file) + 1); strcpy(py_pathtmp, py_file); py_path = malloc(strlen(py_file) + 20) ; sprintf(py_path,"PYTHONPATH=%s",dirname(py_pathtmp)) ; putenv(py_path) ; /* setup python module name, function name */ py_filetmp = malloc(strlen(py_file) + 1); strcpy(py_filetmp, py_file); py_module = (char *) basename(py_filetmp); ext = strrchr(py_module, '.'); if (ext) ext[0] = '\0'; /* Initialize the Python interpreter * NOTE: This call is a no-op on subsequent calls, as we do not * call PyFinalize(). This * a) avoids the overhead of repeatedly reloading the interpreter * b) allows the use of global variables for persisting data in the * routing / rewriting functions between calls. */ Py_Initialize(); /* Load python module */ pName = PyString_FromString(py_module); pModule = PyImport_Import(pName); if (pModule == NULL) { slog_error(client, "Python module <%s> did not load", py_module); goto finish; } /* Prepare to call python function */ pFunc = PyObject_GetAttrString(pModule, py_function); if (!pFunc) { slog_error(client, "Python Function <%s> not found in module <%s>", py_function, py_module); goto finish; } if (!PyCallable_Check(pFunc)) { slog_error(client, "Python Function <%s> in module <%s> is not callable!", py_function, py_module); goto finish; } /* Call function with two arguments - username and query_str */ pArgs = PyTuple_New(2); pValue = PyString_FromString(username); PyTuple_SetItem(pArgs, 0, pValue); pValue = PyString_FromString(query_str); PyTuple_SetItem(pArgs, 1, pValue); pValue = PyObject_CallObject(pFunc, pArgs); if (pValue == NULL) { slog_error(client, "Python Function <%s> failed to return a value", py_function); goto finish; } if (PyString_Check(pValue)) { res = malloc(strlen(PyString_AsString(pValue)) + 1); strcpy(res, PyString_AsString(pValue)); } else { res = NULL; } finish: if (PyErr_Occurred()) { PyErr_Fetch(&ptype, &perror, &ptraceback); slog_error(client, "Python error: %s", PyString_AsString(perror)); } free(py_pathtmp); free(py_filetmp); free(py_path); Py_XDECREF(pName); Py_XDECREF(pModule); Py_XDECREF(pFunc); Py_XDECREF(pArgs); Py_XDECREF(pValue); return res; }