3 * $Header: /cvsroot/pgpool/pgpool-II/pool_auth.c,v 1.15.2.2 2009/09/23 02:03:12 t-ishii Exp $
5 * pgpool: a language independent connection pool server for PostgreSQL
6 * written by Tatsuo Ishii
8 * Copyright (c) 2003-2008 PgPool Global Development Group
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby
12 * granted, provided that the above copyright notice appear in all
13 * copies and that both that copyright notice and this permission
14 * notice appear in supporting documentation, and that the name of the
15 * author not be used in advertising or publicity pertaining to
16 * distribution of the software without specific, written prior
17 * permission. The author makes no representations about the
18 * suitability of this software for any purpose. It is provided "as
19 * is" without express or implied warranty.
21 * pool_auth.c: authenticaton stuff
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
39 #define AUTHFAIL_ERRORCODE "28000"
41 static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor);
42 static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
43 static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
44 static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
47 * do authentication against backend. if success return 0 otherwise non 0.
49 int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
60 protoMajor = MAJOR(cp);
62 kind = pool_read_kind(cp);
71 /* we assume error response at this stage is likely version
72 * protocol mismatch (v3 frontend vs. v2 backend). So we throw
73 * a V2 protocol error response in the hope that v3 frontend
74 * will negotiate again using v2 protocol.
76 pool_log("pool_do_auth: maybe protocol version mismatch (current version %d)", protoMajor);
77 ErrorResponse(frontend, cp);
82 pool_error("pool_do_auth: expect \"R\" got %c", kind);
87 * message length (v3 only)
89 if (protoMajor == PROTO_MAJOR_V3 && pool_read_message_length(cp) < 0)
91 pool_error("Failed to read the authentication packet length. \
92 This is likely caused by the inconsistency of auth method among DB nodes. \
93 In this case you can check the previous error messages (hint: length field) \
94 from pool_read_message_length and recheck the pg_hba.conf settings.");
99 * read authentication request kind.
101 * 0: authentication ok
104 * 3: clear text password
109 * in replication mode, we only support kind = 0, 3. this is because to "salt"
110 * cannot be replicated.
111 * in non replication mode, we support kind = 0, 3, 4, 5
114 authkind = pool_read_int(cp);
117 pool_error("pool_do_auth: read auth kind failed");
121 authkind = ntohl(authkind);
128 pool_write(frontend, "R", 1);
130 if (protoMajor == PROTO_MAJOR_V3)
133 pool_write(frontend, &msglen, sizeof(msglen));
137 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
141 MASTER(cp)->auth_kind = 0;
144 /* clear text password authentication? */
145 else if (authkind == 3)
147 for (i=0;i<NUM_BACKENDS;i++)
149 if (!VALID_BACKEND(i))
152 pool_debug("trying clear text password authentication");
154 authkind = do_clear_text_password(CONNECTION(cp, i), frontend, 0, protoMajor);
158 pool_error("do_clear_text_password failed in slot %d", i);
164 /* crypt authentication? */
165 else if (authkind == 4)
167 for (i=0;i<NUM_BACKENDS;i++)
169 if (!VALID_BACKEND(i))
172 pool_debug("trying crypt authentication");
174 authkind = do_crypt(CONNECTION(cp, i), frontend, 0, protoMajor);
178 pool_error("do_crypt_text_password failed in slot %d", i);
184 /* md5 authentication? */
185 else if (authkind == 5)
187 if (!RAW_MODE && NUM_BACKENDS > 1)
189 pool_send_error_message(frontend, protoMajor, AUTHFAIL_ERRORCODE,
190 "MD5 authentication is unsupported in replication, master-slave and parallel modes.",
197 for (i=0;i<NUM_BACKENDS;i++)
199 if (!VALID_BACKEND(i))
202 pool_debug("trying md5 authentication");
204 authkind = do_md5(CONNECTION(cp, i), frontend, 0, protoMajor);
208 pool_error("do_md5failed in slot %d", i);
216 pool_error("pool_do_auth: unsupported auth kind received: %d", authkind);
222 pool_error("pool_do_auth: backend does not return authentication ok");
227 * authentication ok. now read pid and secret key from the
232 kind = pool_read_kind(cp);
235 pool_error("pool_do_auth: failed to read kind before BackendKeyData");
238 else if (kind == 'K')
241 if (protoMajor == PROTO_MAJOR_V3)
246 /* process parameter status */
247 if (ParameterStatus(frontend, cp) != POOL_CONTINUE)
249 pool_flush(frontend);
253 /* process notice message */
254 if (SimpleForwardToFrontend(kind, frontend, cp))
256 pool_flush(frontend);
259 /* process error message */
261 SimpleForwardToFrontend(kind, frontend, cp);
262 pool_flush(frontend);
267 pool_error("pool_do_auth: unknown response \"%c\" before processing BackendKeyData",
279 /* process notice message */
280 if (NoticeResponse(frontend, cp) != POOL_CONTINUE)
284 /* process error message */
286 ErrorResponse(frontend, cp);
291 pool_error("pool_do_auth: unknown response \"%c\" before processing V2 BackendKeyData",
300 * message length (V3 only)
302 if (protoMajor == PROTO_MAJOR_V3)
306 pool_error("pool_do_auth: expect \"K\" got %c", kind);
310 if ((length = pool_read_message_length(cp)) != 12)
312 pool_error("pool_do_auth: invalid messages length(%d) for BackendKeyData", length);
318 * OK, read pid and secret key
320 for (i=0;i<NUM_BACKENDS;i++)
322 if (VALID_BACKEND(i))
325 if (pool_read(CONNECTION(cp, i), &pid, sizeof(pid)) < 0)
327 pool_error("pool_do_auth: failed to read pid in slot %d", i);
331 CONNECTION_SLOT(cp, i)->pid = cp->info[i].pid = pid;
334 if (pool_read(CONNECTION(cp, i), &key, sizeof(key)) < 0)
336 pool_error("pool_do_auth: failed to read key in slot %d", i);
339 CONNECTION_SLOT(cp, i)->key = cp->info[i].key = key;
344 sp = MASTER_CONNECTION(cp)->sp;
345 cp->info->major = sp->major;
346 cp->info->minor = sp->minor;
347 strncpy(cp->info->database, sp->database, sizeof(cp->info->database) - 1);
348 strncpy(cp->info->user, sp->user, sizeof(cp->info->user) - 1);
349 cp->info->counter = 1;
351 return pool_send_auth_ok(frontend, pid, key, protoMajor);
355 * do re-authentication for reused connection. if success return 0 otherwise non 0.
357 int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
362 protoMajor = MAJOR(cp);
364 switch(MASTER(cp)->auth_kind)
372 /* clear text password */
373 status = do_clear_text_password(MASTER(cp), frontend, 1, protoMajor);
378 status = do_crypt(MASTER(cp), frontend, 1, protoMajor);
383 status = do_md5(MASTER(cp), frontend, 1, protoMajor);
387 pool_error("pool_do_reauth: unknown authentication request code %d",
388 MASTER(cp)->auth_kind);
396 pool_write(frontend, "R", 1);
398 if (protoMajor == PROTO_MAJOR_V3)
401 pool_write(frontend, &msglen, sizeof(msglen));
405 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
412 pool_debug("pool_do_reauth: authentication failed");
416 return (pool_send_auth_ok(frontend, MASTER_CONNECTION(cp)->pid, MASTER_CONNECTION(cp)->key, protoMajor) != POOL_CONTINUE);
420 * send authentication ok to frontend. if success return 0 otherwise non 0.
422 static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor)
428 if (protoMajor == PROTO_MAJOR_V2)
430 /* return "Authentication OK" to the frontend */
432 pool_write(frontend, &kind, 1);
434 if (pool_write_and_flush(frontend, &len, sizeof(len)) < 0)
441 /* send backend key data */
443 pool_write(frontend, &kind, 1);
444 if (protoMajor == PROTO_MAJOR_V3)
447 pool_write(frontend, &len, sizeof(len));
450 pool_debug("pool_send_auth_ok: send pid %d to frontend", ntohl(pid));
452 pool_write(frontend, &pid, sizeof(pid));
453 if (pool_write_and_flush(frontend, &key, sizeof(key)) < 0)
462 * perform clear text password authetication
464 static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
467 static char password[MAX_PASSWORD_SIZE];
473 if (IS_MASTER_NODE_ID(backend->db_node_id))
475 pool_write(frontend, "R", 1); /* authenticaton */
476 if (protoMajor == PROTO_MAJOR_V3)
479 pool_write(frontend, &len, sizeof(len));
481 kind = htonl(3); /* clear text password authentication */
482 pool_write_and_flush(frontend, &kind, sizeof(kind)); /* indicating clear text password authentication */
484 /* read password packet */
485 if (protoMajor == PROTO_MAJOR_V2)
487 if (pool_read(frontend, &size, sizeof(size)))
489 pool_error("do_clear_text_password: failed to read password packet size");
497 if (pool_read(frontend, &k, sizeof(k)))
499 pool_error("do_clear_text_password: failed to read password packet \"p\"");
504 pool_error("do_clear_text_password: password packet does not start with \"p\"");
507 if (pool_read(frontend, &size, sizeof(size)))
509 pool_error("do_clear_text_password: failed to read password packet size");
514 if ((ntohl(size) - 4) > sizeof(password))
516 pool_error("do_clear_text_password: password is too long (size: %d)", ntohl(size) - 4);
520 if (pool_read(frontend, password, ntohl(size) - 4))
522 pool_error("do_clear_text_password: failed to read password (size: %d)", ntohl(size) - 4);
527 /* connection reusing? */
530 if ((ntohl(size) - 4) != backend->pwd_size)
532 pool_debug("do_clear_text_password; password size does not match in re-authetication");
536 if (memcmp(password, backend->password, backend->pwd_size) != 0)
538 pool_debug("do_clear_text_password; password does not match in re-authetication");
545 /* send password packet to backend */
546 if (protoMajor == PROTO_MAJOR_V3)
547 pool_write(backend, "p", 1);
548 pool_write(backend, &size, sizeof(size));
549 pool_write_and_flush(backend, password, ntohl(size) -4);
550 if (pool_read(backend, &response, sizeof(response)))
552 pool_error("do_clear_text_password: failed to read authentication response");
558 pool_debug("do_clear_text_password: backend does not return R while processing clear text password authentication");
562 if (protoMajor == PROTO_MAJOR_V3)
564 if (pool_read(backend, &len, sizeof(len)))
566 pool_error("do_clear_text_password: failed to read authentication packet size");
572 pool_error("do_clear_text_password: incorrect authentication packet size (%d)", ntohl(len));
577 /* expect to read "Authentication OK" response. kind should be 0... */
578 if (pool_read(backend, &kind, sizeof(kind)))
580 pool_debug("do_clear_text_password: failed to read Authentication OK response");
584 /* if authenticated, save info */
585 if (!reauth && kind == 0)
587 if (IS_MASTER_NODE_ID(backend->db_node_id))
591 pool_write(frontend, "R", 1);
593 if (protoMajor == PROTO_MAJOR_V3)
596 pool_write(frontend, &msglen, sizeof(msglen));
600 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
606 backend->auth_kind = 3;
607 backend->pwd_size = ntohl(size) - 4;
608 memcpy(backend->password, password, backend->pwd_size);
614 * perform crypt authetication
616 static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
620 static char password[MAX_PASSWORD_SIZE];
628 if (pool_read(backend, salt, sizeof(salt)))
630 pool_error("do_crypt: failed to read salt");
636 memcpy(salt, backend->salt, sizeof(salt));
640 if (IS_MASTER_NODE_ID(backend->db_node_id))
642 pool_write(frontend, "R", 1); /* authenticaton */
643 if (protoMajor == PROTO_MAJOR_V3)
646 pool_write(frontend, &len, sizeof(len));
648 kind = htonl(4); /* crypt authentication */
649 pool_write(frontend, &kind, sizeof(kind)); /* indicating crypt authentication */
650 pool_write_and_flush(frontend, salt, sizeof(salt)); /* salt */
652 /* read password packet */
653 if (protoMajor == PROTO_MAJOR_V2)
655 if (pool_read(frontend, &size, sizeof(size)))
657 pool_error("do_crypt: failed to read password packet size");
665 if (pool_read(frontend, &k, sizeof(k)))
667 pool_error("do_crypt_password: failed to read password packet \"p\"");
672 pool_error("do_crypt_password: password packet does not start with \"p\"");
675 if (pool_read(frontend, &size, sizeof(size)))
677 pool_error("do_crypt_password: failed to read password packet size");
682 if ((ntohl(size) - 4) > sizeof(password))
684 pool_error("do_crypt: password is too long(size: %d)", ntohl(size) - 4);
688 if (pool_read(frontend, password, ntohl(size) - 4))
690 pool_error("do_crypt: failed to read password (size: %d)", ntohl(size) - 4);
695 /* connection reusing? */
698 pool_debug("size: %d saved_size: %d", (ntohl(size) - 4), backend->pwd_size);
699 if ((ntohl(size) - 4) != backend->pwd_size)
701 pool_debug("do_crypt: password size does not match in re-authentication");
705 if (memcmp(password, backend->password, backend->pwd_size) != 0)
707 pool_debug("do_crypt: password does not match in re-authentication");
714 /* send password packet to backend */
715 if (protoMajor == PROTO_MAJOR_V3)
716 pool_write(backend, "p", 1);
717 pool_write(backend, &size, sizeof(size));
718 pool_write_and_flush(backend, password, ntohl(size) -4);
719 if (pool_read(backend, &response, sizeof(response)))
721 pool_error("do_crypt: failed to read authentication response");
727 pool_debug("do_crypt: backend does not return R while processing crypt authentication(%02x) DB node id: %d", response, backend->db_node_id);
731 if (protoMajor == PROTO_MAJOR_V3)
733 if (pool_read(backend, &len, sizeof(len)))
735 pool_error("do_clear_text_password: failed to read authentication packet size");
741 pool_error("do_clear_text_password: incorrect authentication packet size (%d)", ntohl(len));
746 /* expect to read "Authentication OK" response. kind should be 0... */
747 if (pool_read(backend, &kind, sizeof(kind)))
749 pool_debug("do_crypt: failed to read Authentication OK response");
753 /* if authenticated, save info */
754 if (!reauth && kind == 0)
758 pool_write(frontend, "R", 1);
760 if (protoMajor == PROTO_MAJOR_V3)
763 pool_write(frontend, &msglen, sizeof(msglen));
767 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
772 backend->auth_kind = 4;
773 backend->pwd_size = ntohl(size) - 4;
774 memcpy(backend->password, password, backend->pwd_size);
775 memcpy(backend->salt, salt, sizeof(salt));
781 * perform MD5 authetication
783 static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
787 static char password[MAX_PASSWORD_SIZE];
795 if (pool_read(backend, salt, sizeof(salt)))
797 pool_error("do_md5: failed to read salt");
800 pool_debug("DB node id: %d salt: %hhx%hhx%hhx%hhx", backend->db_node_id,
801 salt[0], salt[1], salt[2], salt[3]);
805 memcpy(salt, backend->salt, sizeof(salt));
809 if (IS_MASTER_NODE_ID(backend->db_node_id))
811 pool_write(frontend, "R", 1); /* authenticaton */
812 if (protoMajor == PROTO_MAJOR_V3)
815 pool_write(frontend, &len, sizeof(len));
818 pool_write(frontend, &kind, sizeof(kind)); /* indicating MD5 */
819 pool_write_and_flush(frontend, salt, sizeof(salt)); /* salt */
821 /* read password packet */
822 if (protoMajor == PROTO_MAJOR_V2)
824 if (pool_read(frontend, &size, sizeof(size)))
826 pool_error("do_md5: failed to read password packet size");
834 if (pool_read(frontend, &k, sizeof(k)))
836 pool_error("do_md5_password: failed to read password packet \"p\"");
841 pool_error("do_md5_password: password packet does not start with \"p\"");
844 if (pool_read(frontend, &size, sizeof(size)))
846 pool_error("do_md5_password: failed to read password packet size");
851 if ((ntohl(size) - 4) > sizeof(password))
853 pool_error("do_md5: password is too long(size: %d)", ntohl(size) - 4);
857 if (pool_read(frontend, password, ntohl(size) - 4))
859 pool_error("do_md5: failed to read password (size: %d)", ntohl(size) - 4);
864 /* connection reusing? */
867 if ((ntohl(size) - 4) != backend->pwd_size)
869 pool_debug("do_md5; password size does not match in re-authentication");
873 if (memcmp(password, backend->password, backend->pwd_size) != 0)
875 pool_debug("do_md5; password does not match in re-authentication");
882 /* send password packet to backend */
883 if (protoMajor == PROTO_MAJOR_V3)
884 pool_write(backend, "p", 1);
885 pool_write(backend, &size, sizeof(size));
886 pool_write_and_flush(backend, password, ntohl(size) -4);
887 if (pool_read(backend, &response, sizeof(response)))
889 pool_error("do_md5: failed to read authentication response");
895 pool_debug("do_md5: backend does not return R while processing MD5 authentication %c", response);
899 if (protoMajor == PROTO_MAJOR_V3)
901 if (pool_read(backend, &len, sizeof(len)))
903 pool_error("do_md5: failed to read authentication packet size");
909 pool_error("do_clear_text_password: incorrect authentication packet size (%d)", ntohl(len));
914 /* expect to read "Authentication OK" response. kind should be 0... */
915 if (pool_read(backend, &kind, sizeof(kind)))
917 pool_debug("do_md5: failed to read Authentication OK response");
921 /* if authenticated, save info */
922 if (!reauth && kind == 0)
926 pool_write(frontend, "R", 1);
928 if (protoMajor == PROTO_MAJOR_V3)
931 pool_write(frontend, &msglen, sizeof(msglen));
935 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
940 backend->auth_kind = 5;
941 backend->pwd_size = ntohl(size) - 4;
942 memcpy(backend->password, password, backend->pwd_size);
943 memcpy(backend->salt, salt, sizeof(salt));
949 * read message length (V3 only)
951 int pool_read_message_length(POOL_CONNECTION_POOL *cp)
957 /* read message from master node */
958 status = pool_read(CONNECTION(cp, MASTER_NODE_ID), &length0, sizeof(length0));
961 pool_error("pool_read_message_length: error while reading message length in slot %d", MASTER_NODE_ID);
964 length0 = ntohl(length0);
965 pool_debug("pool_read_message_length: slot: %d length: %d", MASTER_NODE_ID, length0);
967 for (i=0;i<NUM_BACKENDS;i++)
969 if (!VALID_BACKEND(i) || IS_MASTER_NODE_ID(i))
974 status = pool_read(CONNECTION(cp, i), &length, sizeof(length));
977 pool_error("pool_read_message_length: error while reading message length in slot %d", i);
981 length = ntohl(length);
982 pool_debug("pool_read_message_length: slot: %d length: %d", i, length);
984 if (length != length0)
986 pool_error("pool_read_message_length: message length (%d) in slot %d does not match with slot 0(%d)", length, i, length0);
993 pool_error("pool_read_message_length: invalid message length (%d)", length);
1001 * read message length2 (V3 only)
1002 * unlike pool_read_message_length, this returns an array of message length.
1003 * The array is in the static storage, thus it will be destroyed by subsequent calls.
1005 int *pool_read_message_length2(POOL_CONNECTION_POOL *cp)
1008 int length, length0;
1010 static int length_array[MAX_CONNECTION_SLOTS];
1012 /* read message from master node */
1013 status = pool_read(CONNECTION(cp, MASTER_NODE_ID), &length0, sizeof(length0));
1016 pool_error("pool_read_message_length2: error while reading message length in slot %d", MASTER_NODE_ID);
1020 length0 = ntohl(length0);
1021 length_array[MASTER_NODE_ID] = length0;
1022 pool_debug("pool_read_message_length2: master slot: %d length: %d", MASTER_NODE_ID, length0);
1023 for (i=0;i<NUM_BACKENDS;i++)
1025 if (VALID_BACKEND(i) && !IS_MASTER_NODE_ID(i))
1027 status = pool_read(CONNECTION(cp, i), &length, sizeof(length));
1030 pool_error("pool_read_message_length2: error while reading message length in slot %d", i);
1034 length = ntohl(length);
1035 pool_debug("pool_read_message_length2: master slot: %d length: %d", i, length);
1037 if (length != length0)
1039 pool_log("pool_read_message_length2: message length (%d) in slot %d does not match with slot 0(%d)", length, i, length0);
1044 pool_error("pool_read_message_length2: invalid message length (%d)", length);
1048 length_array[i] = length;
1052 return &length_array[0];
1055 signed char pool_read_kind(POOL_CONNECTION_POOL *cp)
1063 for (i=0;i<NUM_BACKENDS;i++)
1065 if (!VALID_BACKEND(i))
1070 status = pool_read(CONNECTION(cp, i), &kind, sizeof(kind));
1073 pool_error("pool_read_kind: error while reading message kind");
1077 if (IS_MASTER_NODE_ID(i))
1085 pool_error("pool_read_kind: kind does not match between master(%x) slot[%d] (%x)",
1095 int pool_read_int(POOL_CONNECTION_POOL *cp)
1103 for (i=0;i<NUM_BACKENDS;i++)
1105 if (!VALID_BACKEND(i))
1110 status = pool_read(CONNECTION(cp, i), &data, sizeof(data));
1113 pool_error("pool_read_int: error while reading message data");
1117 if (IS_MASTER_NODE_ID(i))
1125 pool_error("pool_read_int: data does not match between between master(%x) slot[%d] (%x)",