From: Marko Kreen Date: Sat, 16 Nov 2013 19:21:55 +0000 (+0200) Subject: auth_query: make password loading query configurable X-Git-Tag: pgbouncer_1_6_rc1~18 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b79b56b3b164d3da3cc467d1ac746c23309e6a78;p=pgbouncer auth_query: make password loading query configurable --- diff --git a/doc/config.txt b/doc/config.txt index 43e0fbc..9cd3907 100644 --- a/doc/config.txt +++ b/doc/config.txt @@ -115,6 +115,12 @@ any:: databases are configured to log in as specific user. Additionally, the console database allows any user to log in as admin. +==== auth_query ==== + +Query to load user's password from db. + +Default: SELECT usename, passwd FROM pg_shadow WHERE usename=$1 + ==== pool_mode ==== Specifies when a server connection can be reused by other clients. diff --git a/include/bouncer.h b/include/bouncer.h index ad6032e..a8437b7 100644 --- a/include/bouncer.h +++ b/include/bouncer.h @@ -400,6 +400,7 @@ extern usec_t cf_dns_zone_check_period; extern int cf_auth_type; extern char *cf_auth_file; +extern char *cf_auth_query; extern char *cf_pidfile; diff --git a/include/pktbuf.h b/include/pktbuf.h index 24d773a..9ed0e93 100644 --- a/include/pktbuf.h +++ b/include/pktbuf.h @@ -73,6 +73,7 @@ void pktbuf_finish_packet(PktBuf *buf); void pktbuf_write_generic(PktBuf *buf, int type, const char *fmt, ...); void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...); void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...); +void pktbuf_write_ExtQuery(PktBuf *buf, const char *query, int nargs, ...); /* * Shortcuts for actual packets. diff --git a/src/client.c b/src/client.c index 5662f61..8ad9b17 100644 --- a/src/client.c +++ b/src/client.c @@ -92,7 +92,7 @@ static bool send_client_authreq(PgSocket *client) static void start_auth_request(PgSocket *client, const char *username) { int res; - char quoted_username[64], query[128]; + PktBuf *buf; client->auth_user = client->db->auth_user; /* have to fetch user info from db */ @@ -111,9 +111,18 @@ static void start_auth_request(PgSocket *client, const char *username) } client->link->ready = 0; - pg_quote_literal(quoted_username, username, sizeof(quoted_username)); - snprintf(query, sizeof(query), "SELECT usename, passwd FROM pg_shadow WHERE usename=%s", quoted_username); - SEND_generic(res, client->link, 'Q', "s", query); + res = 0; + buf = pktbuf_dynamic(512); + if (buf) { + pktbuf_write_ExtQuery(buf, cf_auth_query, 1, username); + res = pktbuf_send_immediate(buf, client->link); + pktbuf_free(buf); + /* + * Should do instead: + * res = pktbuf_send_queued(buf, client->link); + * but that needs better integration with SBuf. + */ + } if (!res) disconnect_server(client->link, false, "unable to send login query"); } @@ -281,6 +290,10 @@ bool handle_auth_response(PgSocket *client, PktHdr *pkt) { break; case 'C': /* CommandComplete */ break; + case '1': /* ParseComplete */ + break; + case '2': /* BindComplete */ + break; case 'Z': /* ReadyForQuery */ sbuf_prepare_skip(&client->link->sbuf, pkt->len); if (!client->auth_user) { diff --git a/src/main.c b/src/main.c index 9ef693a..d978bf1 100644 --- a/src/main.c +++ b/src/main.c @@ -86,6 +86,7 @@ int cf_tcp_keepintvl; int cf_auth_type = AUTH_MD5; char *cf_auth_file; +char *cf_auth_query; int cf_max_client_conn; int cf_default_pool_size; @@ -177,6 +178,7 @@ CF_ABS("unix_socket_group", CF_STR, cf_unix_socket_group, CF_NO_RELOAD, ""), #endif CF_ABS("auth_type", CF_LOOKUP(auth_type_map), cf_auth_type, 0, "md5"), CF_ABS("auth_file", CF_STR, cf_auth_file, 0, "unconfigured_file"), +CF_ABS("auth_query", CF_STR, cf_auth_query, 0, "SELECT usename, passwd FROM pg_shadow WHERE usename=$1"), CF_ABS("pool_mode", CF_LOOKUP(pool_mode_map), cf_pool_mode, 0, "session"), CF_ABS("max_client_conn", CF_INT, cf_max_client_conn, 0, "100"), CF_ABS("default_pool_size", CF_INT, cf_default_pool_size, 0, "20"), diff --git a/src/pktbuf.c b/src/pktbuf.c index 6be1d85..23d2689 100644 --- a/src/pktbuf.c +++ b/src/pktbuf.c @@ -429,3 +429,44 @@ void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...) pktbuf_finish_packet(buf); } +/* + * Send Parse+Bind+Execute with string parameters. + */ +void pktbuf_write_ExtQuery(PktBuf *buf, const char *query, int nargs, ...) +{ + va_list ap; + const char *val; + int len, i; + + /* Parse */ + pktbuf_write_generic(buf, 'P', "csh", 0, query, 0); + + /* Bind */ + pktbuf_start_packet(buf, 'B'); + pktbuf_put_char(buf, 0); /* portal name */ + pktbuf_put_char(buf, 0); /* query name */ + pktbuf_put_uint16(buf, 0); /* number of parameter format codes */ + pktbuf_put_uint16(buf, nargs); /* number of parameter values */ + + va_start(ap, nargs); + for (i = 0; i < nargs; i++) { + val = va_arg(ap, char *); + len = strlen(val); + pktbuf_put_uint32(buf, len); + pktbuf_put_bytes(buf, val, len); + } + va_end(ap); + + pktbuf_put_uint16(buf, 0); /* number of result-column format codes */ + pktbuf_finish_packet(buf); + + /* Describe */ + pktbuf_write_generic(buf, 'D', "cc", 'P', 0); + + /* Execute */ + pktbuf_write_generic(buf, 'E', "ci", 0, 0); + + /* Sync */ + pktbuf_write_generic(buf, 'S', ""); +} +