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