1 /*
2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
3 *
4 * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Admin console commands.
21 */
22
23 #include "bouncer.h"
24
25 #include <usual/regex.h>
26 #include <usual/netdb.h>
27 #include <usual/endian.h>
28
29 /* regex elements */
30 #define WS0 "[ \t\n\r]*"
31 #define WS1 "[ \t\n\r]+"
32 #define WORD "(\"([^\"]+|\"\")*\"|[0-9a-z_]+)"
33 #define STRING "('([^']|'')*')"
34
35 /* possible max + 1 */
36 #define MAX_GROUPS 10
37
38 /* group numbers */
39 #define CMD_NAME 1
40 #define CMD_ARG 4
41 #define SET_KEY 1
42 #define SET_VAL 4
43
44 typedef bool (*cmd_func_t)(PgSocket *admin, const char *arg);
45 struct cmd_lookup {
46 const char *word;
47 cmd_func_t func;
48 };
49
50 /* CMD [arg]; */
51 static const char cmd_normal_rx[] =
52 "^" WS0 WORD "(" WS1 WORD ")?" WS0 "(;" WS0 ")?$";
53
54 /* SET with simple value */
55 static const char cmd_set_word_rx[] =
56 "^" WS0 "set" WS1 WORD WS0 "(=|to)" WS0 WORD WS0 "(;" WS0 ")?$";
57
58 /* SET with quoted value */
59 static const char cmd_set_str_rx[] =
60 "^" WS0 "set" WS1 WORD WS0 "(=|to)" WS0 STRING WS0 "(;" WS0 ")?$";
61
62 /* compiled regexes */
63 static regex_t rc_cmd;
64 static regex_t rc_set_word;
65 static regex_t rc_set_str;
66
67 static PgPool *admin_pool;
68
69 /* only valid during processing */
70 static const char *current_query;
71
admin_cleanup(void)72 void admin_cleanup(void)
73 {
74 regfree(&rc_cmd);
75 regfree(&rc_set_str);
76 regfree(&rc_set_word);
77 admin_pool = NULL;
78 }
79
syntax_error(PgSocket * admin)80 static bool syntax_error(PgSocket *admin)
81 {
82 return admin_error(admin, "invalid command '%s', use SHOW HELP;",
83 current_query ? current_query : "<no query>");
84 }
85
exec_cmd(struct cmd_lookup * lookup,PgSocket * admin,const char * cmd,const char * arg)86 static bool exec_cmd(struct cmd_lookup *lookup, PgSocket *admin,
87 const char *cmd, const char *arg)
88 {
89 for (; lookup->word; lookup++) {
90 if (strcasecmp(lookup->word, cmd) == 0)
91 return lookup->func(admin, arg);
92 }
93 return syntax_error(admin);
94 }
95
admin_error(PgSocket * admin,const char * fmt,...)96 bool admin_error(PgSocket *admin, const char *fmt, ...)
97 {
98 char str[1024];
99 va_list ap;
100 bool res = true;
101
102 va_start(ap, fmt);
103 vsnprintf(str, sizeof(str), fmt, ap);
104 va_end(ap);
105
106 log_error("%s", str);
107 if (admin)
108 res = send_pooler_error(admin, true, false, str);
109 return res;
110 }
111
count_paused_databases(void)112 static int count_paused_databases(void)
113 {
114 struct List *item;
115 PgDatabase *db;
116 int cnt = 0;
117
118 statlist_for_each(item, &database_list) {
119 db = container_of(item, PgDatabase, head);
120 cnt += db->db_paused;
121 }
122 return cnt;
123 }
124
count_db_active(PgDatabase * db)125 static int count_db_active(PgDatabase *db)
126 {
127 struct List *item;
128 PgPool *pool;
129 int cnt = 0;
130
131 statlist_for_each(item, &pool_list) {
132 pool = container_of(item, PgPool, head);
133 if (pool->db != db)
134 continue;
135 cnt += pool_server_count(pool);
136 }
137 return cnt;
138 }
139
admin_flush(PgSocket * admin,PktBuf * buf,const char * desc)140 bool admin_flush(PgSocket *admin, PktBuf *buf, const char *desc)
141 {
142 pktbuf_write_CommandComplete(buf, desc);
143 pktbuf_write_ReadyForQuery(buf);
144 return pktbuf_send_queued(buf, admin);
145 }
146
admin_ready(PgSocket * admin,const char * desc)147 bool admin_ready(PgSocket *admin, const char *desc)
148 {
149 PktBuf buf;
150 uint8_t tmp[512];
151 pktbuf_static(&buf, tmp, sizeof(tmp));
152 pktbuf_write_CommandComplete(&buf, desc);
153 pktbuf_write_ReadyForQuery(&buf);
154 return pktbuf_send_immediate(&buf, admin);
155 }
156
157 /*
158 * some silly clients start actively messing with server parameters
159 * without checking if thats necessary. Fake some env for them.
160 */
161 struct FakeParam {
162 const char *name;
163 const char *value;
164 };
165
166 static const struct FakeParam fake_param_list[] = {
167 { "client_encoding", "UTF-8" },
168 { "default_transaction_isolation", "read committed" },
169 { "standard_conforming_strings", "on" },
170 { "datestyle", "ISO" },
171 { "timezone", "GMT" },
172 { NULL },
173 };
174
175 /* fake result send, returns if handled */
fake_show(PgSocket * admin,const char * name)176 static bool fake_show(PgSocket *admin, const char *name)
177 {
178 PktBuf *buf;
179 const struct FakeParam *p;
180 bool got = false;
181
182 for (p = fake_param_list; p->name; p++) {
183 if (strcasecmp(name, p->name) == 0) {
184 got = true;
185 break;
186 }
187 }
188
189 if (got) {
190 buf = pktbuf_dynamic(256);
191 if (buf) {
192 pktbuf_write_RowDescription(buf, "s", p->name);
193 pktbuf_write_DataRow(buf, "s", p->value);
194 admin_flush(admin, buf, "SHOW");
195 } else
196 admin_error(admin, "no mem");
197 }
198 return got;
199 }
200
fake_set(PgSocket * admin,const char * key,const char * val)201 static bool fake_set(PgSocket *admin, const char *key, const char *val)
202 {
203 PktBuf *buf;
204 const struct FakeParam *p;
205 bool got = false;
206
207 for (p = fake_param_list; p->name; p++) {
208 if (strcasecmp(key, p->name) == 0) {
209 got = true;
210 break;
211 }
212 }
213
214 if (got) {
215 buf = pktbuf_dynamic(256);
216 if (buf) {
217 pktbuf_write_Notice(buf, "SET ignored");
218 admin_flush(admin, buf, "SET");
219 } else
220 admin_error(admin, "no mem");
221 }
222 return got;
223 }
224
225 /* Command: SET key = val; */
admin_set(PgSocket * admin,const char * key,const char * val)226 static bool admin_set(PgSocket *admin, const char *key, const char *val)
227 {
228 char tmp[512];
229 bool ok;
230
231 if (fake_set(admin, key, val))
232 return true;
233
234 if (admin->admin_user) {
235 ok = set_config_param(key, val);
236 if (ok) {
237 PktBuf *buf = pktbuf_dynamic(256);
238 if (strstr(key, "_tls_") != NULL) {
239 if (!sbuf_tls_setup())
240 pktbuf_write_Notice(buf, "TLS settings could not be applied, still using old configuration");
241 }
242 snprintf(tmp, sizeof(tmp), "SET %s=%s", key, val);
243 return admin_flush(admin, buf, tmp);
244 } else {
245 return admin_error(admin, "SET failed");
246 }
247 } else
248 return admin_error(admin, "admin access needed");
249 }
250
251 /* send a row with sendmsg, optionally attaching a fd */
send_one_fd(PgSocket * admin,int fd,const char * task,const char * user,const char * db,const char * addr,int port,uint64_t ckey,int link,const char * client_enc,const char * std_strings,const char * datestyle,const char * timezone,const char * password,const uint8_t * scram_client_key,int scram_client_key_len,const uint8_t * scram_server_key,int scram_server_key_len)252 static bool send_one_fd(PgSocket *admin,
253 int fd, const char *task,
254 const char *user, const char *db,
255 const char *addr, int port,
256 uint64_t ckey, int link,
257 const char *client_enc,
258 const char *std_strings,
259 const char *datestyle,
260 const char *timezone,
261 const char *password,
262 const uint8_t *scram_client_key,
263 int scram_client_key_len,
264 const uint8_t *scram_server_key,
265 int scram_server_key_len)
266 {
267 struct msghdr msg;
268 struct cmsghdr *cmsg;
269 struct iovec iovec;
270 ssize_t res;
271 uint8_t cntbuf[CMSG_SPACE(sizeof(int))];
272
273 struct PktBuf *pkt = pktbuf_temp();
274
275 pktbuf_write_DataRow(pkt, "issssiqisssssbb",
276 fd, task, user, db, addr, port, ckey, link,
277 client_enc, std_strings, datestyle, timezone,
278 password,
279 scram_client_key_len, scram_client_key,
280 scram_server_key_len, scram_server_key);
281 if (pkt->failed)
282 return false;
283 iovec.iov_base = pkt->buf;
284 iovec.iov_len = pktbuf_written(pkt);
285
286 /* sending fds */
287 memset(&msg, 0, sizeof(msg));
288 msg.msg_iov = &iovec;
289 msg.msg_iovlen = 1;
290
291 /* attach a fd */
292 if (pga_is_unix(&admin->remote_addr) && admin->own_user && !admin->sbuf.tls) {
293 msg.msg_control = cntbuf;
294 msg.msg_controllen = sizeof(cntbuf);
295
296 cmsg = CMSG_FIRSTHDR(&msg);
297 cmsg->cmsg_level = SOL_SOCKET;
298 cmsg->cmsg_type = SCM_RIGHTS;
299 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
300
301 memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
302 msg.msg_controllen = cmsg->cmsg_len;
303 }
304
305 slog_debug(admin, "sending socket list: fd=%d, len=%d",
306 fd, (int)msg.msg_controllen);
307 if (msg.msg_controllen) {
308 res = safe_sendmsg(sbuf_socket(&admin->sbuf), &msg, 0);
309 } else {
310 res = sbuf_op_send(&admin->sbuf, pkt->buf, pktbuf_written(pkt));
311 }
312 if (res < 0) {
313 log_error("send_one_fd: sendmsg error: %s", strerror(errno));
314 return false;
315 } else if ((size_t)res != iovec.iov_len) {
316 log_error("send_one_fd: partial sendmsg");
317 return false;
318 }
319 return true;
320 }
321
322 /* send a row with sendmsg, optionally attaching a fd */
show_one_fd(PgSocket * admin,PgSocket * sk)323 static bool show_one_fd(PgSocket *admin, PgSocket *sk)
324 {
325 PgAddr *addr = &sk->remote_addr;
326 struct MBuf tmp;
327 VarCache *v = &sk->vars;
328 uint64_t ckey;
329 const struct PStr *client_encoding = v->var_list[VClientEncoding];
330 const struct PStr *std_strings = v->var_list[VStdStr];
331 const struct PStr *datestyle = v->var_list[VDateStyle];
332 const struct PStr *timezone = v->var_list[VTimeZone];
333 char addrbuf[PGADDR_BUF];
334 const char *password = NULL;
335 bool send_scram_keys = false;
336
337 /* Skip TLS sockets */
338 if (sk->sbuf.tls || (sk->link && sk->link->sbuf.tls))
339 return true;
340
341 mbuf_init_fixed_reader(&tmp, sk->cancel_key, 8);
342 if (!mbuf_get_uint64be(&tmp, &ckey))
343 return false;
344
345 if (sk->pool && sk->pool->db->auth_user && sk->login_user && !find_user(sk->login_user->name))
346 password = sk->login_user->passwd;
347
348 /* PAM requires passwords as well since they are not stored externally */
349 if (cf_auth_type == AUTH_PAM && !find_user(sk->login_user->name))
350 password = sk->login_user->passwd;
351
352 if (sk->pool && sk->pool->user && sk->pool->user->has_scram_keys)
353 send_scram_keys = true;
354
355 return send_one_fd(admin, sbuf_socket(&sk->sbuf),
356 is_server_socket(sk) ? "server" : "client",
357 sk->login_user ? sk->login_user->name : NULL,
358 sk->pool ? sk->pool->db->name : NULL,
359 pga_ntop(addr, addrbuf, sizeof(addrbuf)),
360 pga_port(addr),
361 ckey,
362 sk->link ? sbuf_socket(&sk->link->sbuf) : 0,
363 client_encoding ? client_encoding->str : NULL,
364 std_strings ? std_strings->str : NULL,
365 datestyle ? datestyle->str : NULL,
366 timezone ? timezone->str : NULL,
367 password,
368 send_scram_keys ? sk->pool->user->scram_ClientKey : NULL,
369 send_scram_keys ? (int) sizeof(sk->pool->user->scram_ClientKey) : -1,
370 send_scram_keys ? sk->pool->user->scram_ServerKey : NULL,
371 send_scram_keys ? (int) sizeof(sk->pool->user->scram_ServerKey) : -1);
372 }
373
show_pooler_cb(void * arg,int fd,const PgAddr * a)374 static bool show_pooler_cb(void *arg, int fd, const PgAddr *a)
375 {
376 char buf[PGADDR_BUF];
377
378 return send_one_fd(arg, fd, "pooler", NULL, NULL,
379 pga_ntop(a, buf, sizeof(buf)), pga_port(a), 0, 0,
380 NULL, NULL, NULL, NULL, NULL, NULL, -1, NULL, -1);
381 }
382
383 /* send a row with sendmsg, optionally attaching a fd */
show_pooler_fds(PgSocket * admin)384 static bool show_pooler_fds(PgSocket *admin)
385 {
386 return for_each_pooler_fd(show_pooler_cb, admin);
387 }
388
show_fds_from_list(PgSocket * admin,struct StatList * list)389 static bool show_fds_from_list(PgSocket *admin, struct StatList *list)
390 {
391 struct List *item;
392 PgSocket *sk;
393 bool res = true;
394
395 statlist_for_each(item, list) {
396 sk = container_of(item, PgSocket, head);
397 res = show_one_fd(admin, sk);
398 if (!res)
399 break;
400 }
401 return res;
402 }
403
find_or_register_database(PgSocket * admin,const char * name)404 static PgDatabase *find_or_register_database(PgSocket *admin, const char *name)
405 {
406 PgDatabase *db = find_database(name);
407 if (db == NULL) {
408 db = register_auto_database(name);
409 if (db != NULL) {
410 slog_info(admin,
411 "registered new auto-database: %s", name);
412 }
413 }
414 return db;
415 }
416
417 /*
418 * Command: SHOW FDS
419 *
420 * If privileged connection, send also actual fds
421 */
admin_show_fds(PgSocket * admin,const char * arg)422 static bool admin_show_fds(PgSocket *admin, const char *arg)
423 {
424 struct List *item;
425 PgPool *pool;
426 bool res;
427
428 /*
429 * Dangerous to show to everybody:
430 * - can lock pooler as code flips async option
431 * - show cancel keys for all users
432 * - shows passwords (md5) for dynamic users
433 */
434 if (!admin->admin_user)
435 return admin_error(admin, "admin access needed");
436
437 /*
438 * It's very hard to send it reliably over in async manner,
439 * so turn async off for this resultset.
440 */
441 socket_set_nonblocking(sbuf_socket(&admin->sbuf), 0);
442
443 /*
444 * send resultset
445 */
446 SEND_RowDescription(res, admin, "issssiqisssssbb",
447 "fd", "task",
448 "user", "database",
449 "addr", "port",
450 "cancel", "link",
451 "client_encoding", "std_strings",
452 "datestyle", "timezone", "password",
453 "scram_client_key", "scram_server_key");
454 if (res)
455 res = show_pooler_fds(admin);
456
457 if (res)
458 res = show_fds_from_list(admin, &login_client_list);
459
460 statlist_for_each(item, &pool_list) {
461 pool = container_of(item, PgPool, head);
462 if (pool->db->admin)
463 continue;
464 res = res && show_fds_from_list(admin, &pool->active_client_list);
465 res = res && show_fds_from_list(admin, &pool->waiting_client_list);
466 res = res && show_fds_from_list(admin, &pool->active_server_list);
467 res = res && show_fds_from_list(admin, &pool->idle_server_list);
468 res = res && show_fds_from_list(admin, &pool->used_server_list);
469 res = res && show_fds_from_list(admin, &pool->tested_server_list);
470 res = res && show_fds_from_list(admin, &pool->new_server_list);
471 if (!res)
472 break;
473 }
474 if (res)
475 res = admin_ready(admin, "SHOW");
476
477 /* turn async back on */
478 socket_set_nonblocking(sbuf_socket(&admin->sbuf), 1);
479
480 return res;
481 }
482
483 /* Command: SHOW DATABASES */
admin_show_databases(PgSocket * admin,const char * arg)484 static bool admin_show_databases(PgSocket *admin, const char *arg)
485 {
486 PgDatabase *db;
487 struct List *item;
488 const char *f_user;
489 PktBuf *buf;
490 struct CfValue cv;
491 const char *pool_mode_str;
492
493 cv.extra = pool_mode_map;
494 buf = pktbuf_dynamic(256);
495 if (!buf) {
496 admin_error(admin, "no mem");
497 return true;
498 }
499
500 pktbuf_write_RowDescription(buf, "ssissiiisiiii",
501 "name", "host", "port",
502 "database", "force_user", "pool_size", "min_pool_size", "reserve_pool",
503 "pool_mode", "max_connections", "current_connections", "paused", "disabled");
504 statlist_for_each(item, &database_list) {
505 db = container_of(item, PgDatabase, head);
506
507 f_user = db->forced_user ? db->forced_user->name : NULL;
508 pool_mode_str = NULL;
509 cv.value_p = &db->pool_mode;
510 if (db->pool_mode != POOL_INHERIT)
511 pool_mode_str = cf_get_lookup(&cv);
512 pktbuf_write_DataRow(buf, "ssissiiisiiii",
513 db->name, db->host, db->port,
514 db->dbname, f_user,
515 db->pool_size >= 0 ? db->pool_size : cf_default_pool_size,
516 db->min_pool_size >= 0 ? db->min_pool_size : cf_min_pool_size,
517 db->res_pool_size >= 0 ? db->res_pool_size : cf_res_pool_size,
518 pool_mode_str,
519 database_max_connections(db),
520 db->connection_count,
521 db->db_paused,
522 db->db_disabled);
523 }
524 admin_flush(admin, buf, "SHOW");
525 return true;
526 }
527
528
529 /* Command: SHOW LISTS */
admin_show_lists(PgSocket * admin,const char * arg)530 static bool admin_show_lists(PgSocket *admin, const char *arg)
531 {
532 PktBuf *buf = pktbuf_dynamic(256);
533 if (!buf) {
534 admin_error(admin, "no mem");
535 return true;
536 }
537 pktbuf_write_RowDescription(buf, "si", "list", "items");
538 #define SENDLIST(name, size) pktbuf_write_DataRow(buf, "si", (name), (size))
539 SENDLIST("databases", statlist_count(&database_list));
540 SENDLIST("users", statlist_count(&user_list));
541 SENDLIST("pools", statlist_count(&pool_list));
542 SENDLIST("free_clients", slab_free_count(client_cache));
543 SENDLIST("used_clients", slab_active_count(client_cache));
544 SENDLIST("login_clients", statlist_count(&login_client_list));
545 SENDLIST("free_servers", slab_free_count(server_cache));
546 SENDLIST("used_servers", slab_active_count(server_cache));
547 {
548 int names, zones, qry, pend;
549 adns_info(adns, &names, &zones, &qry, &pend);
550 SENDLIST("dns_names", names);
551 SENDLIST("dns_zones", zones);
552 SENDLIST("dns_queries", qry);
553 SENDLIST("dns_pending", pend);
554 }
555 admin_flush(admin, buf, "SHOW");
556 return true;
557 }
558
559 /* Command: SHOW USERS */
admin_show_users(PgSocket * admin,const char * arg)560 static bool admin_show_users(PgSocket *admin, const char *arg)
561 {
562 PgUser *user;
563 struct List *item;
564 PktBuf *buf = pktbuf_dynamic(256);
565 struct CfValue cv;
566 const char *pool_mode_str;
567
568 if (!buf) {
569 admin_error(admin, "no mem");
570 return true;
571 }
572 cv.extra = pool_mode_map;
573
574 pktbuf_write_RowDescription(buf, "ss", "name", "pool_mode");
575 statlist_for_each(item, &user_list) {
576 user = container_of(item, PgUser, head);
577 pool_mode_str = NULL;
578 cv.value_p = &user->pool_mode;
579 if (user->pool_mode != POOL_INHERIT)
580 pool_mode_str = cf_get_lookup(&cv);
581
582 pktbuf_write_DataRow(buf, "ss", user->name, pool_mode_str);
583 }
584 admin_flush(admin, buf, "SHOW");
585 return true;
586 }
587
588 #define SKF_STD "sssssisiTTiiissis"
589 #define SKF_DBG "sssssisiTTiiissisiiiiiii"
590
socket_header(PktBuf * buf,bool debug)591 static void socket_header(PktBuf *buf, bool debug)
592 {
593 pktbuf_write_RowDescription(buf, debug ? SKF_DBG : SKF_STD,
594 "type", "user", "database", "state",
595 "addr", "port", "local_addr", "local_port",
596 "connect_time", "request_time",
597 "wait", "wait_us", "close_needed",
598 "ptr", "link", "remote_pid", "tls",
599 /* debug follows */
600 "recv_pos", "pkt_pos", "pkt_remain",
601 "send_pos", "send_remain",
602 "pkt_avail", "send_avail");
603 }
604
adr2txt(const PgAddr * adr,char * dst,unsigned dstlen)605 static void adr2txt(const PgAddr *adr, char *dst, unsigned dstlen)
606 {
607 pga_ntop(adr, dst, dstlen);
608 }
609
socket_row(PktBuf * buf,PgSocket * sk,const char * state,bool debug)610 static void socket_row(PktBuf *buf, PgSocket *sk, const char *state, bool debug)
611 {
612 int pkt_avail = 0, send_avail = 0;
613 int remote_pid;
614 char ptrbuf[128], linkbuf[128];
615 char l_addr[PGADDR_BUF], r_addr[PGADDR_BUF];
616 IOBuf *io = sk->sbuf.io;
617 char infobuf[96] = "";
618 usec_t now = get_cached_time();
619 usec_t wait_time = sk->query_start ? now - sk->query_start : 0;
620
621 if (io) {
622 pkt_avail = iobuf_amount_parse(sk->sbuf.io);
623 send_avail = iobuf_amount_pending(sk->sbuf.io);
624 }
625
626 adr2txt(&sk->remote_addr, r_addr, sizeof(r_addr));
627 adr2txt(&sk->local_addr, l_addr, sizeof(l_addr));
628
629 snprintf(ptrbuf, sizeof(ptrbuf), "%p", sk);
630 if (sk->link)
631 snprintf(linkbuf, sizeof(linkbuf), "%p", sk->link);
632 else
633 linkbuf[0] = 0;
634
635 /* get pid over unix socket */
636 if (pga_is_unix(&sk->remote_addr))
637 remote_pid = sk->remote_addr.scred.pid;
638 else
639 remote_pid = 0;
640 /* if that failed, get it from cancel key */
641 if (is_server_socket(sk) && remote_pid == 0)
642 remote_pid = be32dec(sk->cancel_key);
643
644 if (sk->sbuf.tls)
645 tls_get_connection_info(sk->sbuf.tls, infobuf, sizeof infobuf);
646
647 pktbuf_write_DataRow(buf, debug ? SKF_DBG : SKF_STD,
648 is_server_socket(sk) ? "S" :"C",
649 sk->login_user ? sk->login_user->name : "(nouser)",
650 sk->pool ? sk->pool->db->name : "(nodb)",
651 state, r_addr, pga_port(&sk->remote_addr),
652 l_addr, pga_port(&sk->local_addr),
653 sk->connect_time,
654 sk->request_time,
655 (int)(wait_time / USEC),
656 (int)(wait_time % USEC),
657 sk->close_needed,
658 ptrbuf, linkbuf, remote_pid, infobuf,
659 /* debug */
660 io ? io->recv_pos : 0,
661 io ? io->parse_pos : 0,
662 sk->sbuf.pkt_remain,
663 io ? io->done_pos : 0,
664 0,
665 pkt_avail, send_avail);
666 }
667
668 /* Helper for SHOW CLIENTS/SERVERS/SOCKETS */
show_socket_list(PktBuf * buf,struct StatList * list,const char * state,bool debug)669 static void show_socket_list(PktBuf *buf, struct StatList *list, const char *state, bool debug)
670 {
671 struct List *item;
672 PgSocket *sk;
673
674 statlist_for_each(item, list) {
675 sk = container_of(item, PgSocket, head);
676 socket_row(buf, sk, state, debug);
677 }
678 }
679
680 /* Command: SHOW CLIENTS */
admin_show_clients(PgSocket * admin,const char * arg)681 static bool admin_show_clients(PgSocket *admin, const char *arg)
682 {
683 struct List *item;
684 PgPool *pool;
685 PktBuf *buf = pktbuf_dynamic(256);
686
687 if (!buf) {
688 admin_error(admin, "no mem");
689 return true;
690 }
691
692 socket_header(buf, false);
693 statlist_for_each(item, &pool_list) {
694 pool = container_of(item, PgPool, head);
695
696 show_socket_list(buf, &pool->active_client_list, "active", false);
697 show_socket_list(buf, &pool->waiting_client_list, "waiting", false);
698 }
699
700 admin_flush(admin, buf, "SHOW");
701 return true;
702 }
703
704 /* Command: SHOW SERVERS */
admin_show_servers(PgSocket * admin,const char * arg)705 static bool admin_show_servers(PgSocket *admin, const char *arg)
706 {
707 struct List *item;
708 PgPool *pool;
709 PktBuf *buf;
710
711 buf = pktbuf_dynamic(256);
712 if (!buf) {
713 admin_error(admin, "no mem");
714 return true;
715 }
716
717 socket_header(buf, false);
718 statlist_for_each(item, &pool_list) {
719 pool = container_of(item, PgPool, head);
720 show_socket_list(buf, &pool->active_server_list, "active", false);
721 show_socket_list(buf, &pool->idle_server_list, "idle", false);
722 show_socket_list(buf, &pool->used_server_list, "used", false);
723 show_socket_list(buf, &pool->tested_server_list, "tested", false);
724 show_socket_list(buf, &pool->new_server_list, "new", false);
725 }
726 admin_flush(admin, buf, "SHOW");
727 return true;
728 }
729
730 /* Command: SHOW SOCKETS */
admin_show_sockets(PgSocket * admin,const char * arg)731 static bool admin_show_sockets(PgSocket *admin, const char *arg)
732 {
733 struct List *item;
734 PgPool *pool;
735 PktBuf *buf;
736
737 buf = pktbuf_dynamic(256);
738 if (!buf) {
739 admin_error(admin, "no mem");
740 return true;
741 }
742
743 socket_header(buf, true);
744 statlist_for_each(item, &pool_list) {
745 pool = container_of(item, PgPool, head);
746 show_socket_list(buf, &pool->active_client_list, "cl_active", true);
747 show_socket_list(buf, &pool->waiting_client_list, "cl_waiting", true);
748
749 show_socket_list(buf, &pool->active_server_list, "sv_active", true);
750 show_socket_list(buf, &pool->idle_server_list, "sv_idle", true);
751 show_socket_list(buf, &pool->used_server_list, "sv_used", true);
752 show_socket_list(buf, &pool->tested_server_list, "sv_tested", true);
753 show_socket_list(buf, &pool->new_server_list, "sv_login", true);
754 }
755 show_socket_list(buf, &login_client_list, "cl_login", true);
756 admin_flush(admin, buf, "SHOW");
757 return true;
758 }
759
show_active_socket_list(PktBuf * buf,struct StatList * list,const char * state)760 static void show_active_socket_list(PktBuf *buf, struct StatList *list, const char *state)
761 {
762 struct List *item;
763 statlist_for_each(item, list) {
764 PgSocket *sk = container_of(item, PgSocket, head);
765 if (!sbuf_is_empty(&sk->sbuf))
766 socket_row(buf, sk, state, true);
767 }
768 }
769
770 /* Command: SHOW ACTIVE_SOCKETS */
admin_show_active_sockets(PgSocket * admin,const char * arg)771 static bool admin_show_active_sockets(PgSocket *admin, const char *arg)
772 {
773 struct List *item;
774 PgPool *pool;
775 PktBuf *buf;
776
777 buf = pktbuf_dynamic(256);
778 if (!buf) {
779 admin_error(admin, "no mem");
780 return true;
781 }
782
783 socket_header(buf, true);
784 statlist_for_each(item, &pool_list) {
785 pool = container_of(item, PgPool, head);
786 show_active_socket_list(buf, &pool->active_client_list, "cl_active");
787 show_active_socket_list(buf, &pool->waiting_client_list, "cl_waiting");
788
789 show_active_socket_list(buf, &pool->active_server_list, "sv_active");
790 show_active_socket_list(buf, &pool->idle_server_list, "sv_idle");
791 show_active_socket_list(buf, &pool->used_server_list, "sv_used");
792 show_active_socket_list(buf, &pool->tested_server_list, "sv_tested");
793 show_active_socket_list(buf, &pool->new_server_list, "sv_login");
794 }
795 show_active_socket_list(buf, &login_client_list, "cl_login");
796 admin_flush(admin, buf, "SHOW");
797 return true;
798 }
799
800 /* Command: SHOW POOLS */
admin_show_pools(PgSocket * admin,const char * arg)801 static bool admin_show_pools(PgSocket *admin, const char *arg)
802 {
803 struct List *item;
804 PgPool *pool;
805 PktBuf *buf;
806 PgSocket *waiter;
807 usec_t now = get_cached_time();
808 usec_t max_wait;
809 struct CfValue cv;
810 int pool_mode;
811
812 cv.extra = pool_mode_map;
813 cv.value_p = &pool_mode;
814 buf = pktbuf_dynamic(256);
815 if (!buf) {
816 admin_error(admin, "no mem");
817 return true;
818 }
819 pktbuf_write_RowDescription(buf, "ssiiiiiiiiiis",
820 "database", "user",
821 "cl_active", "cl_waiting",
822 "cl_cancel_req",
823 "sv_active", "sv_idle",
824 "sv_used", "sv_tested",
825 "sv_login", "maxwait",
826 "maxwait_us", "pool_mode");
827 statlist_for_each(item, &pool_list) {
828 pool = container_of(item, PgPool, head);
829 waiter = first_socket(&pool->waiting_client_list);
830 max_wait = (waiter && waiter->query_start) ? now - waiter->query_start : 0;
831 pool_mode = pool_pool_mode(pool);
832 pktbuf_write_DataRow(buf, "ssiiiiiiiiiis",
833 pool->db->name, pool->user->name,
834 statlist_count(&pool->active_client_list),
835 statlist_count(&pool->waiting_client_list),
836 statlist_count(&pool->cancel_req_list),
837 statlist_count(&pool->active_server_list),
838 statlist_count(&pool->idle_server_list),
839 statlist_count(&pool->used_server_list),
840 statlist_count(&pool->tested_server_list),
841 statlist_count(&pool->new_server_list),
842 /* how long is the oldest client waited */
843 (int)(max_wait / USEC),
844 (int)(max_wait % USEC),
845 cf_get_lookup(&cv));
846 }
847 admin_flush(admin, buf, "SHOW");
848 return true;
849 }
850
slab_stat_cb(void * arg,const char * slab_name,unsigned size,unsigned free,unsigned total)851 static void slab_stat_cb(void *arg, const char *slab_name,
852 unsigned size, unsigned free,
853 unsigned total)
854 {
855 PktBuf *buf = arg;
856 unsigned alloc = total * size;
857 pktbuf_write_DataRow(buf, "siiii", slab_name,
858 size, total - free, free, alloc);
859 }
860
861 /* Command: SHOW MEM */
admin_show_mem(PgSocket * admin,const char * arg)862 static bool admin_show_mem(PgSocket *admin, const char *arg)
863 {
864 PktBuf *buf;
865
866 buf = pktbuf_dynamic(256);
867 if (!buf) {
868 admin_error(admin, "no mem");
869 return true;
870 }
871 pktbuf_write_RowDescription(buf, "siiii", "name",
872 "size", "used", "free", "memtotal");
873 slab_stats(slab_stat_cb, buf);
874 admin_flush(admin, buf, "SHOW");
875 return true;
876 }
877
878 /* Command: SHOW DNS_HOSTS */
879
dns_name_cb(void * arg,const char * name,const struct addrinfo * ai,usec_t ttl)880 static void dns_name_cb(void *arg, const char *name, const struct addrinfo *ai, usec_t ttl)
881 {
882 PktBuf *buf = arg;
883 char *s, *end;
884 char adrs[1024];
885 usec_t now = get_cached_time();
886
887 end = adrs + sizeof(adrs) - 2;
888 for (s = adrs; ai && s < end; ai = ai->ai_next) {
889 if (s != adrs)
890 *s++ = ',';
891 sa2str(ai->ai_addr, s, end - s);
892 s += strlen(s);
893 }
894 *s = 0;
895
896 /*
897 * Ttl can be smaller than now if we are waiting for dns reply for long.
898 *
899 * It's better to show 0 in that case as otherwise it confuses users into
900 * thinking that there is large ttl for the name.
901 */
902 pktbuf_write_DataRow(buf, "sqs", name, ttl < now ? 0 : (ttl - now) / USEC, adrs);
903 }
904
admin_show_dns_hosts(PgSocket * admin,const char * arg)905 static bool admin_show_dns_hosts(PgSocket *admin, const char *arg)
906 {
907 PktBuf *buf;
908
909 buf = pktbuf_dynamic(256);
910 if (!buf) {
911 admin_error(admin, "no mem");
912 return true;
913 }
914 pktbuf_write_RowDescription(buf, "sqs", "hostname", "ttl", "addrs");
915 adns_walk_names(adns, dns_name_cb, buf);
916 admin_flush(admin, buf, "SHOW");
917 return true;
918 }
919
920 /* Command: SHOW DNS_ZONES */
921
dns_zone_cb(void * arg,const char * name,uint32_t serial,int nhosts)922 static void dns_zone_cb(void *arg, const char *name, uint32_t serial, int nhosts)
923 {
924 PktBuf *buf = arg;
925 pktbuf_write_DataRow(buf, "sqi", name, (uint64_t)serial, nhosts);
926 }
927
admin_show_dns_zones(PgSocket * admin,const char * arg)928 static bool admin_show_dns_zones(PgSocket *admin, const char *arg)
929 {
930 PktBuf *buf;
931
932 buf = pktbuf_dynamic(256);
933 if (!buf) {
934 admin_error(admin, "no mem");
935 return true;
936 }
937 pktbuf_write_RowDescription(buf, "sqi", "zonename", "serial", "count");
938 adns_walk_zones(adns, dns_zone_cb, buf);
939 admin_flush(admin, buf, "SHOW");
940 return true;
941 }
942
943 /* Command: SHOW CONFIG */
944
show_one_param(void * arg,const char * name,const char * val,const char * defval,bool reloadable)945 static void show_one_param(void *arg, const char *name, const char *val, const char *defval, bool reloadable)
946 {
947 PktBuf *buf = arg;
948 pktbuf_write_DataRow(buf, "ssss", name, val, defval,
949 reloadable ? "yes" : "no");
950 }
951
admin_show_config(PgSocket * admin,const char * arg)952 static bool admin_show_config(PgSocket *admin, const char *arg)
953 {
954 PktBuf *buf;
955
956 buf = pktbuf_dynamic(256);
957 if (!buf) {
958 admin_error(admin, "no mem");
959 return true;
960 }
961
962 pktbuf_write_RowDescription(buf, "ssss", "key", "value", "default", "changeable");
963
964 config_for_each(show_one_param, buf);
965
966 admin_flush(admin, buf, "SHOW");
967
968 return true;
969 }
970
971 /* Command: RELOAD */
admin_cmd_reload(PgSocket * admin,const char * arg)972 static bool admin_cmd_reload(PgSocket *admin, const char *arg)
973 {
974 if (arg && *arg)
975 return syntax_error(admin);
976
977 if (!admin->admin_user)
978 return admin_error(admin, "admin access needed");
979
980 log_info("RELOAD command issued");
981 load_config();
982 if (!sbuf_tls_setup())
983 log_error("TLS configuration could not be reloaded, keeping old configuration");
984 return admin_ready(admin, "RELOAD");
985 }
986
987 /* Command: SHUTDOWN */
admin_cmd_shutdown(PgSocket * admin,const char * arg)988 static bool admin_cmd_shutdown(PgSocket *admin, const char *arg)
989 {
990 if (arg && *arg)
991 return syntax_error(admin);
992
993 if (!admin->admin_user)
994 return admin_error(admin, "admin access needed");
995
996 /*
997 * note: new pooler expects unix socket file gone when it gets
998 * event from fd. Currently atexit() cleanup should be called
999 * before closing open sockets.
1000 */
1001 log_info("SHUTDOWN command issued");
1002 cf_shutdown = 2;
1003 event_base_loopbreak(pgb_event_base);
1004
1005 return true;
1006 }
1007
full_resume(void)1008 static void full_resume(void)
1009 {
1010 int tmp_mode = cf_pause_mode;
1011 cf_pause_mode = P_NONE;
1012 if (tmp_mode == P_SUSPEND)
1013 resume_all();
1014
1015 /* avoid surprise later if cf_shutdown stays set */
1016 if (cf_shutdown) {
1017 log_info("canceling shutdown");
1018 cf_shutdown = 0;
1019 }
1020 }
1021
1022 /* Command: RESUME */
admin_cmd_resume(PgSocket * admin,const char * arg)1023 static bool admin_cmd_resume(PgSocket *admin, const char *arg)
1024 {
1025 if (!admin->admin_user)
1026 return admin_error(admin, "admin access needed");
1027
1028 if (!arg[0]) {
1029 log_info("RESUME command issued");
1030 if (cf_pause_mode != P_NONE)
1031 full_resume();
1032 else
1033 return admin_error(admin, "pooler is not paused/suspended");
1034 } else {
1035 PgDatabase *db = find_database(arg);
1036 log_info("RESUME '%s' command issued", arg);
1037 if (db == NULL)
1038 return admin_error(admin, "no such database: %s", arg);
1039 if (!db->db_paused)
1040 return admin_error(admin, "database %s is not paused", arg);
1041 db->db_paused = false;
1042 }
1043 return admin_ready(admin, "RESUME");
1044 }
1045
1046 /* Command: SUSPEND */
admin_cmd_suspend(PgSocket * admin,const char * arg)1047 static bool admin_cmd_suspend(PgSocket *admin, const char *arg)
1048 {
1049 if (arg && *arg)
1050 return syntax_error(admin);
1051
1052 if (!admin->admin_user)
1053 return admin_error(admin, "admin access needed");
1054
1055 if (cf_pause_mode)
1056 return admin_error(admin, "already suspended/paused");
1057
1058 /* suspend needs to be able to flush buffers */
1059 if (count_paused_databases() > 0)
1060 return admin_error(admin, "cannot suspend with paused databases");
1061
1062 log_info("SUSPEND command issued");
1063 cf_pause_mode = P_SUSPEND;
1064 admin->wait_for_response = true;
1065 suspend_pooler();
1066
1067 g_suspend_start = get_cached_time();
1068
1069 return true;
1070 }
1071
1072 /* Command: PAUSE */
admin_cmd_pause(PgSocket * admin,const char * arg)1073 static bool admin_cmd_pause(PgSocket *admin, const char *arg)
1074 {
1075 if (!admin->admin_user)
1076 return admin_error(admin, "admin access needed");
1077
1078 if (cf_pause_mode)
1079 return admin_error(admin, "already suspended/paused");
1080
1081 if (!arg[0]) {
1082 log_info("PAUSE command issued");
1083 cf_pause_mode = P_PAUSE;
1084 admin->wait_for_response = true;
1085 } else {
1086 PgDatabase *db;
1087 log_info("PAUSE '%s' command issued", arg);
1088 db = find_or_register_database(admin, arg);
1089 if (db == NULL)
1090 return admin_error(admin, "no such database: %s", arg);
1091 if (db == admin->pool->db)
1092 return admin_error(admin, "cannot pause admin db: %s", arg);
1093 db->db_paused = true;
1094 if (count_db_active(db) > 0)
1095 admin->wait_for_response = true;
1096 else
1097 return admin_ready(admin, "PAUSE");
1098 }
1099
1100 return true;
1101 }
1102
1103 /* Command: RECONNECT */
admin_cmd_reconnect(PgSocket * admin,const char * arg)1104 static bool admin_cmd_reconnect(PgSocket *admin, const char *arg)
1105 {
1106 if (!admin->admin_user)
1107 return admin_error(admin, "admin access needed");
1108
1109 if (!arg[0]) {
1110 struct List *item;
1111 PgPool *pool;
1112
1113 log_info("RECONNECT command issued");
1114 statlist_for_each(item, &pool_list) {
1115 pool = container_of(item, PgPool, head);
1116 if (pool->db->admin)
1117 continue;
1118 tag_database_dirty(pool->db);
1119 }
1120 } else {
1121 PgDatabase *db;
1122
1123 log_info("RECONNECT '%s' command issued", arg);
1124 db = find_or_register_database(admin, arg);
1125 if (db == NULL)
1126 return admin_error(admin, "no such database: %s", arg);
1127 if (db == admin->pool->db)
1128 return admin_error(admin, "cannot reconnect admin db: %s", arg);
1129 tag_database_dirty(db);
1130 }
1131
1132 return admin_ready(admin, "RECONNECT");
1133 }
1134
1135 /* Command: DISABLE */
admin_cmd_disable(PgSocket * admin,const char * arg)1136 static bool admin_cmd_disable(PgSocket *admin, const char *arg)
1137 {
1138 PgDatabase *db;
1139
1140 if (!admin->admin_user)
1141 return admin_error(admin, "admin access needed");
1142
1143 if (!arg[0])
1144 return admin_error(admin, "a database is required");
1145
1146 log_info("DISABLE '%s' command issued", arg);
1147 db = find_or_register_database(admin, arg);
1148 if (db == NULL)
1149 return admin_error(admin, "no such database: %s", arg);
1150 if (db->admin)
1151 return admin_error(admin, "cannot disable admin db: %s", arg);
1152
1153 db->db_disabled = true;
1154 return admin_ready(admin, "DISABLE");
1155 }
1156
1157 /* Command: ENABLE */
admin_cmd_enable(PgSocket * admin,const char * arg)1158 static bool admin_cmd_enable(PgSocket *admin, const char *arg)
1159 {
1160 PgDatabase *db;
1161
1162 if (!admin->admin_user)
1163 return admin_error(admin, "admin access needed");
1164
1165 if (!arg[0])
1166 return admin_error(admin, "a database is required");
1167
1168 log_info("ENABLE '%s' command issued", arg);
1169 db = find_database(arg);
1170 if (db == NULL)
1171 return admin_error(admin, "no such database: %s", arg);
1172 if (db->admin)
1173 return admin_error(admin, "cannot disable admin db: %s", arg);
1174
1175 db->db_disabled = false;
1176 return admin_ready(admin, "ENABLE");
1177 }
1178
1179 /* Command: KILL */
admin_cmd_kill(PgSocket * admin,const char * arg)1180 static bool admin_cmd_kill(PgSocket *admin, const char *arg)
1181 {
1182 struct List *item, *tmp;
1183 PgDatabase *db;
1184 PgPool *pool;
1185
1186 if (!admin->admin_user)
1187 return admin_error(admin, "admin access needed");
1188
1189 if (cf_pause_mode)
1190 return admin_error(admin, "already suspended/paused");
1191
1192 if (!arg[0])
1193 return admin_error(admin, "a database is required");
1194
1195 log_info("KILL '%s' command issued", arg);
1196 db = find_or_register_database(admin, arg);
1197 if (db == NULL)
1198 return admin_error(admin, "no such database: %s", arg);
1199 if (db == admin->pool->db)
1200 return admin_error(admin, "cannot kill admin db: %s", arg);
1201
1202 db->db_paused = true;
1203 statlist_for_each_safe(item, &pool_list, tmp) {
1204 pool = container_of(item, PgPool, head);
1205 if (pool->db == db)
1206 kill_pool(pool);
1207 }
1208
1209 return admin_ready(admin, "KILL");
1210 }
1211
1212 /* Command: WAIT_CLOSE */
admin_cmd_wait_close(PgSocket * admin,const char * arg)1213 static bool admin_cmd_wait_close(PgSocket *admin, const char *arg)
1214 {
1215 if (!admin->admin_user)
1216 return admin_error(admin, "admin access needed");
1217
1218 if (!arg[0]) {
1219 struct List *item;
1220 PgPool *pool;
1221 int active = 0;
1222
1223 log_info("WAIT_CLOSE command issued");
1224 statlist_for_each(item, &pool_list) {
1225 PgDatabase *db;
1226
1227 pool = container_of(item, PgPool, head);
1228 db = pool->db;
1229 db->db_wait_close = true;
1230 active += count_db_active(db);
1231 }
1232 if (active > 0)
1233 admin->wait_for_response = true;
1234 else
1235 return admin_ready(admin, "WAIT_CLOSE");
1236 } else {
1237 PgDatabase *db;
1238
1239 log_info("WAIT_CLOSE '%s' command issued", arg);
1240 db = find_or_register_database(admin, arg);
1241 if (db == NULL)
1242 return admin_error(admin, "no such database: %s", arg);
1243 if (db == admin->pool->db)
1244 return admin_error(admin, "cannot wait in admin db: %s", arg);
1245 db->db_wait_close = true;
1246 if (count_db_active(db) > 0)
1247 admin->wait_for_response = true;
1248 else
1249 return admin_ready(admin, "WAIT_CLOSE");
1250 }
1251
1252 return true;
1253 }
1254
1255 /* extract substring from regex group */
copy_arg(const char * src,regmatch_t * glist,int gnum,char * dst,unsigned dstmax,char qchar)1256 static bool copy_arg(const char *src, regmatch_t *glist,
1257 int gnum, char *dst, unsigned dstmax,
1258 char qchar)
1259 {
1260 regmatch_t *g = &glist[gnum];
1261 unsigned len;
1262 const char *s;
1263 char *d = dst;
1264 unsigned i;
1265
1266 /* no match, if regex allows, it must be fine */
1267 if (g->rm_so < 0 || g->rm_eo < 0) {
1268 dst[0] = 0;
1269 return true;
1270 }
1271
1272 len = g->rm_eo - g->rm_so;
1273 s = src + g->rm_so;
1274
1275 /* too big value */
1276 if (len >= dstmax) {
1277 dst[0] = 0;
1278 return false;
1279 }
1280
1281 /* copy and unquote */
1282 if (*s == qchar) {
1283 for (i = 1; i < len - 1; i++) {
1284 if (s[i] == qchar && s[i+1] == qchar)
1285 i++;
1286 *d++ = s[i];
1287 }
1288 len = d - dst;
1289 } else {
1290 memcpy(dst, s, len);
1291 }
1292 dst[len] = 0;
1293 return true;
1294 }
1295
admin_show_help(PgSocket * admin,const char * arg)1296 static bool admin_show_help(PgSocket *admin, const char *arg)
1297 {
1298 bool res;
1299 SEND_generic(res, admin, 'N',
1300 "sssss",
1301 "SNOTICE", "C00000", "MConsole usage",
1302 "D\n\tSHOW HELP|CONFIG|DATABASES"
1303 "|POOLS|CLIENTS|SERVERS|USERS|VERSION\n"
1304 "\tSHOW FDS|SOCKETS|ACTIVE_SOCKETS|LISTS|MEM\n"
1305 "\tSHOW DNS_HOSTS|DNS_ZONES\n"
1306 "\tSHOW STATS|STATS_TOTALS|STATS_AVERAGES|TOTALS\n"
1307 "\tSET key = arg\n"
1308 "\tRELOAD\n"
1309 "\tPAUSE [<db>]\n"
1310 "\tRESUME [<db>]\n"
1311 "\tDISABLE <db>\n"
1312 "\tENABLE <db>\n"
1313 "\tRECONNECT [<db>]\n"
1314 "\tKILL <db>\n"
1315 "\tSUSPEND\n"
1316 "\tSHUTDOWN\n",
1317 "\tWAIT_CLOSE [<db>]", "");
1318 if (res)
1319 res = admin_ready(admin, "SHOW");
1320 return res;
1321 }
1322
admin_show_version(PgSocket * admin,const char * arg)1323 static bool admin_show_version(PgSocket *admin, const char *arg)
1324 {
1325 PktBuf *buf;
1326
1327 buf = pktbuf_dynamic(128);
1328 if (!buf) {
1329 admin_error(admin, "no mem");
1330 return true;
1331 }
1332
1333 pktbuf_write_RowDescription(buf, "s", "version");
1334 pktbuf_write_DataRow(buf, "s", PACKAGE_STRING);
1335
1336 admin_flush(admin, buf, "SHOW");
1337
1338 return true;
1339 }
1340
admin_show_stats(PgSocket * admin,const char * arg)1341 static bool admin_show_stats(PgSocket *admin, const char *arg)
1342 {
1343 return admin_database_stats(admin, &pool_list);
1344 }
1345
admin_show_stats_totals(PgSocket * admin,const char * arg)1346 static bool admin_show_stats_totals(PgSocket *admin, const char *arg)
1347 {
1348 return admin_database_stats_totals(admin, &pool_list);
1349 }
1350
admin_show_stats_averages(PgSocket * admin,const char * arg)1351 static bool admin_show_stats_averages(PgSocket *admin, const char *arg)
1352 {
1353 return admin_database_stats_averages(admin, &pool_list);
1354 }
1355
admin_show_totals(PgSocket * admin,const char * arg)1356 static bool admin_show_totals(PgSocket *admin, const char *arg)
1357 {
1358 return show_stat_totals(admin, &pool_list);
1359 }
1360
1361
1362 static struct cmd_lookup show_map [] = {
1363 {"clients", admin_show_clients},
1364 {"config", admin_show_config},
1365 {"databases", admin_show_databases},
1366 {"fds", admin_show_fds},
1367 {"help", admin_show_help},
1368 {"lists", admin_show_lists},
1369 {"pools", admin_show_pools},
1370 {"servers", admin_show_servers},
1371 {"sockets", admin_show_sockets},
1372 {"active_sockets", admin_show_active_sockets},
1373 {"stats", admin_show_stats},
1374 {"stats_totals", admin_show_stats_totals},
1375 {"stats_averages", admin_show_stats_averages},
1376 {"users", admin_show_users},
1377 {"version", admin_show_version},
1378 {"totals", admin_show_totals},
1379 {"mem", admin_show_mem},
1380 {"dns_hosts", admin_show_dns_hosts},
1381 {"dns_zones", admin_show_dns_zones},
1382 {NULL, NULL}
1383 };
1384
admin_cmd_show(PgSocket * admin,const char * arg)1385 static bool admin_cmd_show(PgSocket *admin, const char *arg)
1386 {
1387 if (fake_show(admin, arg))
1388 return true;
1389 return exec_cmd(show_map, admin, arg, NULL);
1390 }
1391
1392 static struct cmd_lookup cmd_list [] = {
1393 {"disable", admin_cmd_disable},
1394 {"enable", admin_cmd_enable},
1395 {"kill", admin_cmd_kill},
1396 {"pause", admin_cmd_pause},
1397 {"reconnect", admin_cmd_reconnect},
1398 {"reload", admin_cmd_reload},
1399 {"resume", admin_cmd_resume},
1400 {"select", admin_cmd_show},
1401 {"show", admin_cmd_show},
1402 {"shutdown", admin_cmd_shutdown},
1403 {"suspend", admin_cmd_suspend},
1404 {"wait_close", admin_cmd_wait_close},
1405 {NULL, NULL}
1406 };
1407
1408 /* handle user query */
admin_parse_query(PgSocket * admin,const char * q)1409 static bool admin_parse_query(PgSocket *admin, const char *q)
1410 {
1411 regmatch_t grp[MAX_GROUPS];
1412 char cmd[16];
1413 char arg[64];
1414 char val[256];
1415 bool res;
1416 bool ok;
1417
1418 current_query = q;
1419
1420 if (regexec(&rc_cmd, q, MAX_GROUPS, grp, 0) == 0) {
1421 ok = copy_arg(q, grp, CMD_NAME, cmd, sizeof(cmd), '"');
1422 if (!ok)
1423 goto failed;
1424 ok = copy_arg(q, grp, CMD_ARG, arg, sizeof(arg), '"');
1425 if (!ok)
1426 goto failed;
1427 res = exec_cmd(cmd_list, admin, cmd, arg);
1428 } else if (regexec(&rc_set_str, q, MAX_GROUPS, grp, 0) == 0) {
1429 ok = copy_arg(q, grp, SET_KEY, arg, sizeof(arg), '"');
1430 if (!ok || !arg[0])
1431 goto failed;
1432 ok = copy_arg(q, grp, SET_VAL, val, sizeof(val), '\'');
1433 if (!ok)
1434 goto failed;
1435 res = admin_set(admin, arg, val);
1436 } else if (regexec(&rc_set_word, q, MAX_GROUPS, grp, 0) == 0) {
1437 ok = copy_arg(q, grp, SET_KEY, arg, sizeof(arg), '"');
1438 if (!ok || !arg[0])
1439 goto failed;
1440 ok = copy_arg(q, grp, SET_VAL, val, sizeof(val), '"');
1441 if (!ok)
1442 goto failed;
1443 res = admin_set(admin, arg, val);
1444 } else
1445 res = syntax_error(admin);
1446 done:
1447 current_query = NULL;
1448 if (!res)
1449 disconnect_client(admin, true, "failure");
1450 return res;
1451 failed:
1452 res = admin_error(admin, "bad arguments");
1453 goto done;
1454 }
1455
1456 /* handle packets */
admin_handle_client(PgSocket * admin,PktHdr * pkt)1457 bool admin_handle_client(PgSocket *admin, PktHdr *pkt)
1458 {
1459 const char *q;
1460 bool res;
1461
1462 /* don't tolerate partial packets */
1463 if (incomplete_pkt(pkt)) {
1464 disconnect_client(admin, true, "incomplete pkt");
1465 return false;
1466 }
1467
1468 switch (pkt->type) {
1469 case 'Q':
1470 if (!mbuf_get_string(&pkt->data, &q)) {
1471 disconnect_client(admin, true, "incomplete query");
1472 return false;
1473 }
1474 log_debug("got admin query: %s", q);
1475 res = admin_parse_query(admin, q);
1476 if (res)
1477 sbuf_prepare_skip(&admin->sbuf, pkt->len);
1478 return res;
1479 case 'X':
1480 disconnect_client(admin, false, "close req");
1481 break;
1482 default:
1483 admin_error(admin, "unsupported pkt type: %d", pkt_desc(pkt));
1484 disconnect_client(admin, true, "bad pkt");
1485 break;
1486 }
1487 return false;
1488 }
1489
1490 /**
1491 * Client is unauthenticated, look if it wants to connect
1492 * to special "pgbouncer" user.
1493 */
admin_pre_login(PgSocket * client,const char * username)1494 bool admin_pre_login(PgSocket *client, const char *username)
1495 {
1496 client->admin_user = false;
1497 client->own_user = false;
1498
1499 /* tag same uid as special */
1500 if (pga_is_unix(&client->remote_addr)) {
1501 uid_t peer_uid;
1502 gid_t peer_gid;
1503 int res;
1504
1505 res = getpeereid(sbuf_socket(&client->sbuf), &peer_uid, &peer_gid);
1506 if (res >= 0 && peer_uid == getuid()
1507 && strcmp("pgbouncer", username) == 0)
1508 {
1509 client->login_user = admin_pool->db->forced_user;
1510 client->own_user = true;
1511 client->admin_user = true;
1512 slog_info(client, "pgbouncer access from unix socket");
1513 return true;
1514 }
1515 }
1516
1517 /*
1518 * auth_type=any does not keep original username around,
1519 * so username based check has to take place here
1520 */
1521 if (cf_auth_type == AUTH_ANY) {
1522 if (strlist_contains(cf_admin_users, username)) {
1523 client->login_user = admin_pool->db->forced_user;
1524 client->admin_user = true;
1525 return true;
1526 } else if (strlist_contains(cf_stats_users, username)) {
1527 client->login_user = admin_pool->db->forced_user;
1528 return true;
1529 }
1530 }
1531 return false;
1532 }
1533
admin_post_login(PgSocket * client)1534 bool admin_post_login(PgSocket *client)
1535 {
1536 const char *username = client->login_user->name;
1537
1538 if (cf_auth_type == AUTH_ANY)
1539 return true;
1540
1541 if (client->admin_user || strlist_contains(cf_admin_users, username)) {
1542 client->admin_user = true;
1543 return true;
1544 } else if (strlist_contains(cf_stats_users, username)) {
1545 return true;
1546 }
1547
1548 disconnect_client(client, true, "not allowed");
1549 return false;
1550 }
1551
1552 /* init special database and query parsing */
admin_setup(void)1553 void admin_setup(void)
1554 {
1555 PgDatabase *db;
1556 PgPool *pool;
1557 PgUser *user;
1558 PktBuf *msg;
1559 int res;
1560
1561 /* fake database */
1562 db = add_database("pgbouncer");
1563 if (!db)
1564 die("no memory for admin database");
1565
1566 db->port = cf_listen_port;
1567 db->pool_size = 2;
1568 db->admin = true;
1569 db->pool_mode = POOL_STMT;
1570 if (!force_user(db, "pgbouncer", ""))
1571 die("no mem on startup - cannot alloc pgbouncer user");
1572
1573 /* fake pool */
1574 pool = get_pool(db, db->forced_user);
1575 if (!pool)
1576 die("cannot create admin pool?");
1577 admin_pool = pool;
1578
1579 /* user */
1580 user = find_user("pgbouncer");
1581 if (!user) {
1582 /* fake user with disabled psw */
1583 user = add_user("pgbouncer", "");
1584 if (!user)
1585 die("cannot create admin user?");
1586 }
1587
1588 /* prepare welcome */
1589 msg = pktbuf_dynamic(128);
1590 if (!msg)
1591 die("out of memory");
1592 pktbuf_write_AuthenticationOk(msg);
1593 pktbuf_write_ParameterStatus(msg, "server_version", PACKAGE_VERSION "/bouncer");
1594 pktbuf_write_ParameterStatus(msg, "client_encoding", "UTF8");
1595 pktbuf_write_ParameterStatus(msg, "server_encoding", "UTF8");
1596 pktbuf_write_ParameterStatus(msg, "DateStyle", "ISO");
1597 pktbuf_write_ParameterStatus(msg, "TimeZone", "GMT");
1598 pktbuf_write_ParameterStatus(msg, "standard_conforming_strings", "on");
1599 pktbuf_write_ParameterStatus(msg, "is_superuser", "on");
1600
1601 if (msg->failed)
1602 die("admin welcome failed");
1603
1604 pool->welcome_msg = msg;
1605 pool->welcome_msg_ready = true;
1606
1607 msg = pktbuf_dynamic(128);
1608 if (!msg)
1609 die("cannot create admin startup pkt");
1610 db->startup_params = msg;
1611 pktbuf_put_string(msg, "database");
1612 db->dbname = "pgbouncer";
1613 pktbuf_put_string(msg, db->dbname);
1614
1615 /* initialize regexes */
1616 res = regcomp(&rc_cmd, cmd_normal_rx, REG_EXTENDED | REG_ICASE);
1617 if (res != 0)
1618 fatal("cmd regex compilation error");
1619 res = regcomp(&rc_set_word, cmd_set_word_rx, REG_EXTENDED | REG_ICASE);
1620 if (res != 0)
1621 fatal("set/word regex compilation error");
1622 res = regcomp(&rc_set_str, cmd_set_str_rx, REG_EXTENDED | REG_ICASE);
1623 if (res != 0)
1624 fatal("set/str regex compilation error");
1625 }
1626
admin_pause_done(void)1627 void admin_pause_done(void)
1628 {
1629 struct List *item, *tmp;
1630 PgSocket *admin;
1631 bool res;
1632
1633 statlist_for_each_safe(item, &admin_pool->active_client_list, tmp) {
1634 admin = container_of(item, PgSocket, head);
1635 if (!admin->wait_for_response)
1636 continue;
1637
1638 switch (cf_pause_mode) {
1639 case P_PAUSE:
1640 res = admin_ready(admin, "PAUSE");
1641 break;
1642 case P_SUSPEND:
1643 res = admin_ready(admin, "SUSPEND");
1644 break;
1645 default:
1646 if (count_paused_databases() > 0)
1647 res = admin_ready(admin, "PAUSE");
1648 else {
1649 /* FIXME */
1650 fatal("admin_pause_done: bad state");
1651 res = false;
1652 }
1653 }
1654
1655 if (!res)
1656 disconnect_client(admin, false, "dead admin");
1657 else
1658 admin->wait_for_response = false;
1659 }
1660
1661 if (statlist_empty(&admin_pool->active_client_list)
1662 && cf_pause_mode == P_SUSPEND)
1663 {
1664 log_info("admin disappeared when suspended, doing RESUME");
1665 cf_pause_mode = P_NONE;
1666 resume_all();
1667 }
1668 }
1669
admin_wait_close_done(void)1670 void admin_wait_close_done(void)
1671 {
1672 struct List *item, *tmp;
1673 PgSocket *admin;
1674 bool res;
1675
1676 statlist_for_each_safe(item, &admin_pool->active_client_list, tmp) {
1677 admin = container_of(item, PgSocket, head);
1678 if (!admin->wait_for_response)
1679 continue;
1680
1681 res = admin_ready(admin, "WAIT_CLOSE");
1682
1683 if (!res)
1684 disconnect_client(admin, false, "dead admin");
1685 else
1686 admin->wait_for_response = false;
1687 }
1688 }
1689
1690 /* admin on console has pressed ^C */
admin_handle_cancel(PgSocket * admin)1691 void admin_handle_cancel(PgSocket *admin)
1692 {
1693 /* weird, but no reason to fail */
1694 if (!admin->wait_for_response)
1695 slog_warning(admin, "admin cancel request for non-waiting client?");
1696
1697 if (cf_pause_mode != P_NONE)
1698 full_resume();
1699 }
1700