]> git.8kb.co.uk Git - pgpool-ii/pgpool-ii_2.2.5/blob - pool_auth.c
Attempt to send a proper failure message to frontend when authentication
[pgpool-ii/pgpool-ii_2.2.5] / pool_auth.c
1 /* -*-pgsql-c-*- */
2 /*
3  * $Header: /cvsroot/pgpool/pgpool-II/pool_auth.c,v 1.15.2.2 2009/09/23 02:03:12 t-ishii Exp $
4  *
5  * pgpool: a language independent connection pool server for PostgreSQL
6  * written by Tatsuo Ishii
7  *
8  * Copyright (c) 2003-2008      PgPool Global Development Group
9  *
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.
20  *
21  * pool_auth.c: authenticaton stuff
22  *
23 */
24
25 #include "pool.h"
26
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
32 #endif
33 #ifdef HAVE_PARAM_H
34 #include <param.h>
35 #endif
36 #include <errno.h>
37 #include <string.h>
38 #include <stdlib.h>
39
40 #define AUTHFAIL_ERRORCODE "28000"
41
42 static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor);
43 static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
44 static void pool_send_auth_fail(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
45 static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
46 static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
47
48
49 /*
50 * do authentication against backend. if success return 0 otherwise non 0.
51 */
52 int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
53 {
54         signed char kind;
55         int pid;
56         int key;
57         int protoMajor;
58         int length;
59         int authkind;
60         int i;
61         StartupPacket *sp;
62
63         protoMajor = MAJOR(cp);
64
65         kind = pool_read_kind(cp);
66         if (kind < 0)
67         {
68                 return -1;
69         }
70
71         /* error response? */
72         if (kind == 'E')
73         {
74                 /* we assume error response at this stage is likely version
75                  * protocol mismatch (v3 frontend vs. v2 backend). So we throw
76                  * a V2 protocol error response in the hope that v3 frontend
77                  * will negotiate again using v2 protocol.
78                  */
79                 pool_log("pool_do_auth: maybe protocol version mismatch (current version %d)", protoMajor);
80                 ErrorResponse(frontend, cp);
81                 return -1;
82         }
83         else if (kind != 'R')
84         {
85                 pool_error("pool_do_auth: expect \"R\" got %c", kind);
86                 return -1;
87         }
88
89         /*
90          * message length (v3 only)
91          */
92         if (protoMajor == PROTO_MAJOR_V3 && pool_read_message_length(cp) < 0)
93         {
94                 pool_error("Failed to read the authentication packet length. \
95 This is likely caused by the inconsistency of auth method among DB nodes. \
96 In this case you can check the previous error messages (hint: length field) \
97 from pool_read_message_length and recheck the pg_hba.conf settings.");
98                 return -1;
99         }
100
101         /*
102          * read authentication request kind.
103          *
104          * 0: authentication ok
105          * 1: kerberos v4
106          * 2: kerberos v5
107          * 3: clear text password
108          * 4: crypt password
109          * 5: md5 password
110          * 6: scm credential
111          *
112          * in replication mode, we only support  kind = 0, 3. this is because to "salt"
113          * cannot be replicated.
114          * in non replication mode, we support kind = 0, 3, 4, 5
115          */
116
117         authkind = pool_read_int(cp);
118         if (authkind < 0)
119         {
120                 pool_error("pool_do_auth: read auth kind failed");
121                 return -1;
122         }
123
124         authkind = ntohl(authkind);
125
126         /* trust? */
127         if (authkind == 0)
128         {
129                 int msglen;
130
131                 pool_write(frontend, "R", 1);
132
133                 if (protoMajor == PROTO_MAJOR_V3)
134                 {
135                         msglen = htonl(8);
136                         pool_write(frontend, &msglen, sizeof(msglen));
137                 }
138
139                 msglen = htonl(0);
140                 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
141                 {
142                         pool_send_auth_fail(frontend, cp);
143                         return -1;
144                 }
145                 MASTER(cp)->auth_kind = 0;
146         }
147
148         /* clear text password authentication? */
149         else if (authkind == 3)
150         {
151                 for (i=0;i<NUM_BACKENDS;i++)
152                 {
153                         if (!VALID_BACKEND(i))
154                                 continue;
155
156                         pool_debug("trying clear text password authentication");
157
158                         authkind = do_clear_text_password(CONNECTION(cp, i), frontend, 0, protoMajor);
159
160                         if (authkind < 0)
161                         {
162                                 pool_error("do_clear_text_password failed in slot %d", i);
163                                 pool_send_auth_fail(frontend, cp);
164                                 return -1;
165                         }
166                 }
167         }
168
169         /* crypt authentication? */
170         else if (authkind == 4)
171         {
172                 for (i=0;i<NUM_BACKENDS;i++)
173                 {
174                         if (!VALID_BACKEND(i))
175                                 continue;
176
177                         pool_debug("trying crypt authentication");
178
179                         authkind = do_crypt(CONNECTION(cp, i), frontend, 0, protoMajor);
180
181                         if (authkind < 0)
182                         {
183                                 pool_error("do_crypt_text_password failed in slot %d", i);
184                                 pool_send_auth_fail(frontend, cp);
185                                 return -1;
186                         }
187                 }
188         }
189
190         /* md5 authentication? */
191         else if (authkind == 5)
192         {
193                 if (!RAW_MODE && NUM_BACKENDS > 1)
194                 {
195                         pool_send_error_message(frontend, protoMajor, AUTHFAIL_ERRORCODE,
196                                                                         "MD5 authentication is unsupported in replication, master-slave and parallel modes.",
197                                                                         "",
198                                                                         "check pg_hba.conf",
199                                                                         __FILE__, __LINE__);
200                         return -1;
201                 }
202
203                 for (i=0;i<NUM_BACKENDS;i++)
204                 {
205                         if (!VALID_BACKEND(i))
206                                 continue;
207
208                         pool_debug("trying md5 authentication");
209
210                         authkind = do_md5(CONNECTION(cp, i), frontend, 0, protoMajor);
211
212                         if (authkind < 0)
213                         {
214                                 pool_error("do_md5failed in slot %d", i);
215                                 pool_send_auth_fail(frontend, cp);
216                                 return -1;
217                         }
218                 }
219         }
220
221         else
222         {
223                 pool_error("pool_do_auth: unsupported auth kind received: %d", authkind);
224                 return -1;
225         }
226
227         if (authkind != 0)
228         {
229                 pool_error("pool_do_auth: backend does not return authentication ok");
230                 return -1;
231         }
232
233         /*
234          * authentication ok. now read pid and secret key from the
235          * backend
236          */
237         for (;;)
238         {
239                 kind = pool_read_kind(cp);
240                 if (kind < 0)
241                 {
242                         pool_error("pool_do_auth: failed to read kind before BackendKeyData");
243                         return -1;
244                 }
245                 else if (kind == 'K')
246                         break;
247
248                 if (protoMajor == PROTO_MAJOR_V3)
249                 {
250                         switch (kind)
251                         {
252                                 case 'S':
253                                         /* process parameter status */
254                                         if (ParameterStatus(frontend, cp) != POOL_CONTINUE)
255                                                 return -1;
256                                         pool_flush(frontend);
257                                         break;
258
259                                 case 'N':
260                                         /* process notice message */
261                                         if (SimpleForwardToFrontend(kind, frontend, cp))
262                                                 return -1;
263                                         pool_flush(frontend);
264                                         break;
265
266                                         /* process error message */
267                                 case 'E':
268                                         SimpleForwardToFrontend(kind, frontend, cp);
269                                         pool_flush(frontend);
270                                         return -1;
271                                         break;
272
273                                 default:
274                                         pool_error("pool_do_auth: unknown response \"%c\" before processing BackendKeyData",
275                                                            kind);
276                                         return -1;
277                                         break;
278                         }
279                 }
280                 else
281                 {
282                         /* V2 case */
283                         switch (kind)
284                         {
285                                 case 'N':
286                                         /* process notice message */
287                                         if (NoticeResponse(frontend, cp) != POOL_CONTINUE)
288                                                 return -1;
289                                         break;
290
291                                         /* process error message */
292                                 case 'E':
293                                         ErrorResponse(frontend, cp);
294                                         return -1;
295                                         break;
296
297                                 default:
298                                         pool_error("pool_do_auth: unknown response \"%c\" before processing V2 BackendKeyData",
299                                                            kind);
300                                         return -1;
301                                         break;
302                         }
303                 }
304         }
305
306         /*
307          * message length (V3 only)
308          */
309         if (protoMajor == PROTO_MAJOR_V3)
310         {
311                 if (kind != 'K')
312                 {
313                         pool_error("pool_do_auth: expect \"K\" got %c", kind);
314                         return -1;
315                 }
316
317                 if ((length = pool_read_message_length(cp)) != 12)
318                 {
319                         pool_error("pool_do_auth: invalid messages length(%d) for BackendKeyData", length);
320                         return -1;
321                 }
322         }
323
324         /*
325          * OK, read pid and secret key
326          */
327         for (i=0;i<NUM_BACKENDS;i++)
328         {
329                 if (VALID_BACKEND(i))
330                 {
331                         /* read pid */
332                         if (pool_read(CONNECTION(cp, i), &pid, sizeof(pid)) < 0)
333                         {
334                                 pool_error("pool_do_auth: failed to read pid in slot %d", i);
335                                 return -1;
336                         }
337
338                         CONNECTION_SLOT(cp, i)->pid = cp->info[i].pid = pid;
339
340                         /* read key */
341                         if (pool_read(CONNECTION(cp, i), &key, sizeof(key)) < 0)
342                         {
343                                 pool_error("pool_do_auth: failed to read key in slot %d", i);
344                                 return -1;
345                         }
346                         CONNECTION_SLOT(cp, i)->key = cp->info[i].key = key;
347
348                 }
349         }
350
351         sp = MASTER_CONNECTION(cp)->sp;
352         cp->info->major = sp->major;
353         cp->info->minor = sp->minor;
354         strncpy(cp->info->database, sp->database, sizeof(cp->info->database) - 1);
355         strncpy(cp->info->user, sp->user, sizeof(cp->info->user) - 1);
356         cp->info->counter = 1;
357
358         return pool_send_auth_ok(frontend, pid, key, protoMajor);
359 }
360
361 /*
362 * do re-authentication for reused connection. if success return 0 otherwise non 0.
363 */
364 int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
365 {
366         int status;
367         int protoMajor;
368
369         protoMajor = MAJOR(cp);
370
371         switch(MASTER(cp)->auth_kind)
372         {
373                 case 0:
374                         /* trust */
375                         status = 0;
376                         break;
377
378                 case 3:
379                         /* clear text password */
380                         status = do_clear_text_password(MASTER(cp), frontend, 1, protoMajor);
381                         break;
382
383                 case 4:
384                         /* crypt password */
385                         status = do_crypt(MASTER(cp), frontend, 1, protoMajor);
386                         break;
387
388                 case 5:
389                         /* md5 password */
390                         status = do_md5(MASTER(cp), frontend, 1, protoMajor);
391                         break;
392
393                 default:
394                         pool_error("pool_do_reauth: unknown authentication request code %d",
395                                            MASTER(cp)->auth_kind);
396                         return -1;
397         }
398
399         if (status == 0)
400         {
401                 int msglen;
402
403                 pool_write(frontend, "R", 1);
404
405                 if (protoMajor == PROTO_MAJOR_V3)
406                 {
407                         msglen = htonl(8);
408                         pool_write(frontend, &msglen, sizeof(msglen));
409                 }
410
411                 msglen = htonl(0);
412                 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
413                 {
414                         return -1;
415                 }
416         }
417         else
418         {
419                 pool_debug("pool_do_reauth: authentication failed");
420                 pool_send_auth_fail(frontend, cp);               
421                 return -1;
422         }
423
424         return (pool_send_auth_ok(frontend, MASTER_CONNECTION(cp)->pid, MASTER_CONNECTION(cp)->key, protoMajor) != POOL_CONTINUE);
425 }
426
427 /*
428 * send authentication failure message text to frontend
429 */
430 static void pool_send_auth_fail(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
431 {
432         int messagelen;
433         char *errmessage;
434         int protoMajor;
435
436         bool send_error_to_frontend = true;
437
438         protoMajor = MAJOR(cp);
439
440         messagelen = strlen(MASTER_CONNECTION(cp)->sp->user) + 100;
441         if ((errmessage = (char *)malloc(messagelen+1)) == NULL)
442         {
443                 pool_error("pool_send_auth_fail_failed: malloc failed: %s", strerror(errno));
444                 child_exit(1);
445         }
446
447         snprintf(errmessage, messagelen, "password authentication failed for user \"%s\"",
448                  MASTER_CONNECTION(cp)->sp->user);
449         if (send_error_to_frontend)
450         pool_send_fatal_message(frontend, protoMajor, "XX000", errmessage,
451                                 "", "", __FILE__, __LINE__);
452         free(errmessage);
453
454
455 /*
456 * send authentication ok to frontend. if success return 0 otherwise non 0.
457 */
458 static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor)
459 {
460         char kind;
461         int len;
462
463 #ifdef NOT_USED
464         if (protoMajor == PROTO_MAJOR_V2)
465         {
466                 /* return "Authentication OK" to the frontend */
467                 kind = 'R';
468                 pool_write(frontend, &kind, 1);
469                 len = htonl(0);
470                 if (pool_write_and_flush(frontend, &len, sizeof(len)) < 0)
471                 {
472                         return -1;
473                 }
474         }
475 #endif
476
477         /* send backend key data */
478         kind = 'K';
479         pool_write(frontend, &kind, 1);
480         if (protoMajor == PROTO_MAJOR_V3)
481         {
482                 len = htonl(12);
483                 pool_write(frontend, &len, sizeof(len));
484         }
485
486         pool_debug("pool_send_auth_ok: send pid %d to frontend", ntohl(pid));
487
488         pool_write(frontend, &pid, sizeof(pid));
489         if (pool_write_and_flush(frontend, &key, sizeof(key)) < 0)
490         {
491                 return -1;
492         }
493
494         return 0;
495 }
496
497 /*
498  * perform clear text password authetication
499  */
500 static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
501 {
502         static int size;
503         static char password[MAX_PASSWORD_SIZE];
504         char response;
505         int kind;
506         int len;
507
508         /* master? */
509         if (IS_MASTER_NODE_ID(backend->db_node_id))
510         {
511                 pool_write(frontend, "R", 1);   /* authenticaton */
512                 if (protoMajor == PROTO_MAJOR_V3)
513                 {
514                         len = htonl(8);
515                         pool_write(frontend, &len, sizeof(len));
516                 }
517                 kind = htonl(3);                /* clear text password authentication */
518                 pool_write_and_flush(frontend, &kind, sizeof(kind));    /* indicating clear text password authentication */
519
520                 /* read password packet */
521                 if (protoMajor == PROTO_MAJOR_V2)
522                 {
523                         if (pool_read(frontend, &size, sizeof(size)))
524                         {
525                                 pool_error("do_clear_text_password: failed to read password packet size");
526                                 return -1;
527                         }
528                 }
529                 else
530                 {
531                         char k;
532
533                         if (pool_read(frontend, &k, sizeof(k)))
534                         {
535                                 pool_error("do_clear_text_password: failed to read password packet \"p\"");
536                                 return -1;
537                         }
538                         if (k != 'p')
539                         {
540                                 pool_error("do_clear_text_password: password packet does not start with \"p\"");
541                                 return -1;
542                         }
543                         if (pool_read(frontend, &size, sizeof(size)))
544                         {
545                                 pool_error("do_clear_text_password: failed to read password packet size");
546                                 return -1;
547                         }
548                 }
549
550                 if ((ntohl(size) - 4) > sizeof(password))
551                 {
552                         pool_error("do_clear_text_password: password is too long (size: %d)", ntohl(size) - 4);
553                         return -1;
554                 }
555
556                 if (pool_read(frontend, password, ntohl(size) - 4))
557                 {
558                         pool_error("do_clear_text_password: failed to read password (size: %d)", ntohl(size) - 4);
559                         return -1;
560                 }
561         }
562
563         /* connection reusing? */
564         if (reauth)
565         {
566                 if ((ntohl(size) - 4) != backend->pwd_size)
567                 {
568                         pool_debug("do_clear_text_password; password size does not match in re-authetication");
569                         return -1;
570                 }
571
572                 if (memcmp(password, backend->password, backend->pwd_size) != 0)
573                 {
574                         pool_debug("do_clear_text_password; password does not match in re-authetication");
575                         return -1;
576                 }
577
578                 return 0;
579         }
580
581         /* send password packet to backend */
582         if (protoMajor == PROTO_MAJOR_V3)
583                 pool_write(backend, "p", 1);
584         pool_write(backend, &size, sizeof(size));
585         pool_write_and_flush(backend, password, ntohl(size) -4);
586         if (pool_read(backend, &response, sizeof(response)))
587         {
588                 pool_error("do_clear_text_password: failed to read authentication response");
589                 return -1;
590         }
591
592         if (response != 'R')
593         {
594                 pool_debug("do_clear_text_password: backend does not return R while processing clear text password authentication");
595                 return -1;
596         }
597
598         if (protoMajor == PROTO_MAJOR_V3)
599         {
600                 if (pool_read(backend, &len, sizeof(len)))
601                 {
602                         pool_error("do_clear_text_password: failed to read authentication packet size");
603                         return -1;
604                 }
605
606                 if (ntohl(len) != 8)
607                 {
608                         pool_error("do_clear_text_password: incorrect authentication packet size (%d)", ntohl(len));
609                         return -1;
610                 }
611         }
612
613         /* expect to read "Authentication OK" response. kind should be 0... */
614         if (pool_read(backend, &kind, sizeof(kind)))
615         {
616                 pool_debug("do_clear_text_password: failed to read Authentication OK response");
617                 return -1;
618         }
619
620         /* if authenticated, save info */
621         if (!reauth && kind == 0)
622         {
623                 if (IS_MASTER_NODE_ID(backend->db_node_id))
624                 {
625                         int msglen;
626
627                         pool_write(frontend, "R", 1);
628
629                         if (protoMajor == PROTO_MAJOR_V3)
630                         {
631                                 msglen = htonl(8);
632                                 pool_write(frontend, &msglen, sizeof(msglen));
633                         }
634
635                         msglen = htonl(0);
636                         if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
637                         {
638                                 return -1;
639                         }
640                 }
641
642                 backend->auth_kind = 3;
643                 backend->pwd_size = ntohl(size) - 4;
644                 memcpy(backend->password, password, backend->pwd_size);
645         }
646         return kind;
647 }
648
649 /*
650  * perform crypt authetication
651  */
652 static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
653 {
654         char salt[2];
655         static int size;
656         static char password[MAX_PASSWORD_SIZE];
657         char response;
658         int kind;
659         int len;
660
661         if (!reauth)
662         {
663                 /* read salt */
664                 if (pool_read(backend, salt, sizeof(salt)))
665                 {
666                         pool_error("do_crypt: failed to read salt");
667                         return -1;
668                 }
669         }
670         else
671         {
672                 memcpy(salt, backend->salt, sizeof(salt));
673         }
674
675         /* master? */
676         if (IS_MASTER_NODE_ID(backend->db_node_id))
677         {
678                 pool_write(frontend, "R", 1);   /* authenticaton */
679                 if (protoMajor == PROTO_MAJOR_V3)
680                 {
681                         len = htonl(10);
682                         pool_write(frontend, &len, sizeof(len));
683                 }
684                 kind = htonl(4);                /* crypt authentication */
685                 pool_write(frontend, &kind, sizeof(kind));      /* indicating crypt authentication */
686                 pool_write_and_flush(frontend, salt, sizeof(salt));             /* salt */
687
688                 /* read password packet */
689                 if (protoMajor == PROTO_MAJOR_V2)
690                 {
691                         if (pool_read(frontend, &size, sizeof(size)))
692                         {
693                                 pool_error("do_crypt: failed to read password packet size");
694                                 return -1;
695                         }
696                 }
697                 else
698                 {
699                         char k;
700
701                         if (pool_read(frontend, &k, sizeof(k)))
702                         {
703                                 pool_error("do_crypt_password: failed to read password packet \"p\"");
704                                 return -1;
705                         }
706                         if (k != 'p')
707                         {
708                                 pool_error("do_crypt_password: password packet does not start with \"p\"");
709                                 return -1;
710                         }
711                         if (pool_read(frontend, &size, sizeof(size)))
712                         {
713                                 pool_error("do_crypt_password: failed to read password packet size");
714                                 return -1;
715                         }
716                 }
717
718                 if ((ntohl(size) - 4) > sizeof(password))
719                 {
720                         pool_error("do_crypt: password is too long(size: %d)", ntohl(size) - 4);
721                         return -1;
722                 }
723
724                 if (pool_read(frontend, password, ntohl(size) - 4))
725                 {
726                         pool_error("do_crypt: failed to read password (size: %d)", ntohl(size) - 4);
727                         return -1;
728                 }
729         }
730
731         /* connection reusing? */
732         if (reauth)
733         {
734                 pool_debug("size: %d saved_size: %d", (ntohl(size) - 4), backend->pwd_size);
735                 if ((ntohl(size) - 4) != backend->pwd_size)
736                 {
737                         pool_debug("do_crypt: password size does not match in re-authentication");
738                         return -1;
739                 }
740
741                 if (memcmp(password, backend->password, backend->pwd_size) != 0)
742                 {
743                         pool_debug("do_crypt: password does not match in re-authentication");
744                         return -1;
745                 }
746
747                 return 0;
748         }
749
750         /* send password packet to backend */
751         if (protoMajor == PROTO_MAJOR_V3)
752                 pool_write(backend, "p", 1);
753         pool_write(backend, &size, sizeof(size));
754         pool_write_and_flush(backend, password, ntohl(size) -4);
755         if (pool_read(backend, &response, sizeof(response)))
756         {
757                 pool_error("do_crypt: failed to read authentication response");
758                 return -1;
759         }
760
761         if (response != 'R')
762         {
763                 pool_debug("do_crypt: backend does not return R while processing crypt authentication(%02x) DB node id: %d", response, backend->db_node_id);
764                 return -1;
765         }
766
767         if (protoMajor == PROTO_MAJOR_V3)
768         {
769                 if (pool_read(backend, &len, sizeof(len)))
770                 {
771                         pool_error("do_clear_text_password: failed to read authentication packet size");
772                         return -1;
773                 }
774
775                 if (ntohl(len) != 8)
776                 {
777                         pool_error("do_clear_text_password: incorrect authentication packet size (%d)", ntohl(len));
778                         return -1;
779                 }
780         }
781
782         /* expect to read "Authentication OK" response. kind should be 0... */
783         if (pool_read(backend, &kind, sizeof(kind)))
784         {
785                 pool_debug("do_crypt: failed to read Authentication OK response");
786                 return -1;
787         }
788
789         /* if authenticated, save info */
790         if (!reauth && kind == 0)
791         {
792                 int msglen;
793
794                 pool_write(frontend, "R", 1);
795
796                 if (protoMajor == PROTO_MAJOR_V3)
797                 {
798                         msglen = htonl(8);
799                         pool_write(frontend, &msglen, sizeof(msglen));
800                 }
801
802                 msglen = htonl(0);
803                 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
804                 {
805                         return -1;
806                 }
807
808                 backend->auth_kind = 4;
809                 backend->pwd_size = ntohl(size) - 4;
810                 memcpy(backend->password, password, backend->pwd_size);
811                 memcpy(backend->salt, salt, sizeof(salt));
812         }
813         return kind;
814 }
815
816 /*
817  * perform MD5 authetication
818  */
819 static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
820 {
821         char salt[4];
822         static int size;
823         static char password[MAX_PASSWORD_SIZE];
824         char response;
825         int kind;
826         int len;
827
828         if (!reauth)
829         {
830                 /* read salt */
831                 if (pool_read(backend, salt, sizeof(salt)))
832                 {
833                         pool_error("do_md5: failed to read salt");
834                         return -1;
835                 }
836                 pool_debug("DB node id: %d salt: %hhx%hhx%hhx%hhx", backend->db_node_id,
837                                    salt[0], salt[1], salt[2], salt[3]);
838         }
839         else
840         {
841                 memcpy(salt, backend->salt, sizeof(salt));
842         }
843
844         /* master? */
845         if (IS_MASTER_NODE_ID(backend->db_node_id))
846         {
847                 pool_write(frontend, "R", 1);   /* authenticaton */
848                 if (protoMajor == PROTO_MAJOR_V3)
849                 {
850                         len = htonl(12);
851                         pool_write(frontend, &len, sizeof(len));
852                 }
853                 kind = htonl(5);
854                 pool_write(frontend, &kind, sizeof(kind));      /* indicating MD5 */
855                 pool_write_and_flush(frontend, salt, sizeof(salt));             /* salt */
856
857                 /* read password packet */
858                 if (protoMajor == PROTO_MAJOR_V2)
859                 {
860                         if (pool_read(frontend, &size, sizeof(size)))
861                         {
862                                 pool_error("do_md5: failed to read password packet size");
863                                 return -1;
864                         }
865                 }
866                 else
867                 {
868                         char k;
869
870                         if (pool_read(frontend, &k, sizeof(k)))
871                         {
872                                 pool_error("do_md5_password: failed to read password packet \"p\"");
873                                 return -1;
874                         }
875                         if (k != 'p')
876                         {
877                                 pool_error("do_md5_password: password packet does not start with \"p\"");
878                                 return -1;
879                         }
880                         if (pool_read(frontend, &size, sizeof(size)))
881                         {
882                                 pool_error("do_md5_password: failed to read password packet size");
883                                 return -1;
884                         }
885                 }
886
887                 if ((ntohl(size) - 4) > sizeof(password))
888                 {
889                         pool_error("do_md5: password is too long(size: %d)", ntohl(size) - 4);
890                         return -1;
891                 }
892
893                 if (pool_read(frontend, password, ntohl(size) - 4))
894                 {
895                         pool_error("do_md5: failed to read password (size: %d)", ntohl(size) - 4);
896                         return -1;
897                 }
898         }
899
900         /* connection reusing? */
901         if (reauth)
902         {
903                 if ((ntohl(size) - 4) != backend->pwd_size)
904                 {
905                         pool_debug("do_md5; password size does not match in re-authentication");
906                         return -1;
907                 }
908
909                 if (memcmp(password, backend->password, backend->pwd_size) != 0)
910                 {
911                         pool_debug("do_md5; password does not match in re-authentication");
912                         return -1;
913                 }
914
915                 return 0;
916         }
917
918         /* send password packet to backend */
919         if (protoMajor == PROTO_MAJOR_V3)
920                 pool_write(backend, "p", 1);
921         pool_write(backend, &size, sizeof(size));
922         pool_write_and_flush(backend, password, ntohl(size) -4);
923         if (pool_read(backend, &response, sizeof(response)))
924         {
925                 pool_error("do_md5: failed to read authentication response");
926                 return -1;
927         }
928
929         if (response != 'R')
930         {
931                 pool_debug("do_md5: backend does not return R while processing MD5 authentication %c", response);
932                 return -1;
933         }
934
935         if (protoMajor == PROTO_MAJOR_V3)
936         {
937                 if (pool_read(backend, &len, sizeof(len)))
938                 {
939                         pool_error("do_md5: failed to read authentication packet size");
940                         return -1;
941                 }
942
943                 if (ntohl(len) != 8)
944                 {
945                         pool_error("do_clear_text_password: incorrect authentication packet size (%d)", ntohl(len));
946                         return -1;
947                 }
948         }
949
950         /* expect to read "Authentication OK" response. kind should be 0... */
951         if (pool_read(backend, &kind, sizeof(kind)))
952         {
953                 pool_debug("do_md5: failed to read Authentication OK response");
954                 return -1;
955         }
956
957         /* if authenticated, save info */
958         if (!reauth && kind == 0)
959         {
960                 int msglen;
961
962                 pool_write(frontend, "R", 1);
963
964                 if (protoMajor == PROTO_MAJOR_V3)
965                 {
966                         msglen = htonl(8);
967                         pool_write(frontend, &msglen, sizeof(msglen));
968                 }
969
970                 msglen = htonl(0);
971                 if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
972                 {
973                         return -1;
974                 }
975
976                 backend->auth_kind = 5;
977                 backend->pwd_size = ntohl(size) - 4;
978                 memcpy(backend->password, password, backend->pwd_size);
979                 memcpy(backend->salt, salt, sizeof(salt));
980         }
981         return kind;
982 }
983
984 /*
985  * read message length (V3 only)
986  */
987 int pool_read_message_length(POOL_CONNECTION_POOL *cp)
988 {
989         int status;
990         int length, length0;
991         int i;
992
993         /* read message from master node */
994         status = pool_read(CONNECTION(cp, MASTER_NODE_ID), &length0, sizeof(length0));
995         if (status < 0)
996         {
997                 pool_error("pool_read_message_length: error while reading message length in slot %d", MASTER_NODE_ID);
998                 return -1;
999         }
1000         length0 = ntohl(length0);
1001         pool_debug("pool_read_message_length: slot: %d length: %d", MASTER_NODE_ID, length0);
1002
1003         for (i=0;i<NUM_BACKENDS;i++)
1004         {
1005                 if (!VALID_BACKEND(i) || IS_MASTER_NODE_ID(i))
1006                 {
1007                         continue;
1008                 }
1009
1010                 status = pool_read(CONNECTION(cp, i), &length, sizeof(length));
1011                 if (status < 0)
1012                 {
1013                         pool_error("pool_read_message_length: error while reading message length in slot %d", i);
1014                         return -1;
1015                 }
1016
1017                 length = ntohl(length);
1018                 pool_debug("pool_read_message_length: slot: %d length: %d", i, length);
1019
1020                 if (length != length0)
1021                 {
1022                         pool_error("pool_read_message_length: message length (%d) in slot %d does not match with slot 0(%d)", length, i, length0);
1023                         return -1;
1024                 }
1025         }
1026
1027         if (length0 < 0)
1028         {
1029                 pool_error("pool_read_message_length: invalid message length (%d)", length);
1030                 return -1;
1031         }
1032
1033         return length0;
1034 }
1035
1036 /*
1037  * read message length2 (V3 only)
1038  * unlike pool_read_message_length, this returns an array of message length.
1039  * The array is in the static storage, thus it will be destroyed by subsequent calls.
1040  */
1041 int *pool_read_message_length2(POOL_CONNECTION_POOL *cp)
1042 {
1043         int status;
1044         int length, length0;
1045         int i;
1046         static int length_array[MAX_CONNECTION_SLOTS];
1047
1048         /* read message from master node */
1049         status = pool_read(CONNECTION(cp, MASTER_NODE_ID), &length0, sizeof(length0));
1050         if (status < 0)
1051         {
1052                 pool_error("pool_read_message_length2: error while reading message length in slot %d", MASTER_NODE_ID);
1053                 return NULL;
1054         }
1055
1056         length0 = ntohl(length0);
1057         length_array[MASTER_NODE_ID] = length0;
1058         pool_debug("pool_read_message_length2: master slot: %d length: %d", MASTER_NODE_ID, length0);
1059         for (i=0;i<NUM_BACKENDS;i++)
1060         {
1061                 if (VALID_BACKEND(i) && !IS_MASTER_NODE_ID(i))
1062                 {
1063                         status = pool_read(CONNECTION(cp, i), &length, sizeof(length));
1064                         if (status < 0)
1065                         {
1066                                 pool_error("pool_read_message_length2: error while reading message length in slot %d", i);
1067                                 return NULL;
1068                         }
1069
1070                         length = ntohl(length);
1071                         pool_debug("pool_read_message_length2: master slot: %d length: %d", i, length);
1072
1073                         if (length != length0)
1074                         {
1075                                 pool_log("pool_read_message_length2: message length (%d) in slot %d does not match with slot 0(%d)", length, i, length0);
1076                         }
1077
1078                         if (length < 0)
1079                         {
1080                                 pool_error("pool_read_message_length2: invalid message length (%d)", length);
1081                                 return NULL;
1082                         }
1083
1084                         length_array[i] = length;
1085                 }
1086
1087         }
1088         return &length_array[0];
1089 }
1090
1091 signed char pool_read_kind(POOL_CONNECTION_POOL *cp)
1092 {
1093         int status;
1094         char kind0, kind;
1095         int i;
1096
1097         kind0 = 0;
1098
1099         for (i=0;i<NUM_BACKENDS;i++)
1100         {
1101                 if (!VALID_BACKEND(i))
1102                 {
1103                         continue;
1104                 }
1105
1106                 status = pool_read(CONNECTION(cp, i), &kind, sizeof(kind));
1107                 if (status < 0)
1108                 {
1109                         pool_error("pool_read_kind: error while reading message kind");
1110                         return -1;
1111                 }
1112
1113                 if (IS_MASTER_NODE_ID(i))
1114                 {
1115                         kind0 = kind;
1116                 }
1117                 else
1118                 {
1119                         if (kind != kind0)
1120                         {
1121                                 pool_error("pool_read_kind: kind does not match between master(%x) slot[%d] (%x)",
1122                                                    kind0, i, kind);
1123                                 return -1;
1124                         }
1125                 }
1126         }
1127
1128         return kind;
1129 }
1130
1131 int pool_read_int(POOL_CONNECTION_POOL *cp)
1132 {
1133         int status;
1134         int data0, data;
1135         int i;
1136
1137         data0 = 0;
1138
1139         for (i=0;i<NUM_BACKENDS;i++)
1140         {
1141                 if (!VALID_BACKEND(i))
1142                 {
1143                         continue;
1144                 }
1145
1146                 status = pool_read(CONNECTION(cp, i), &data, sizeof(data));
1147                 if (status < 0)
1148                 {
1149                         pool_error("pool_read_int: error while reading message data");
1150                         return -1;
1151                 }
1152
1153                 if (IS_MASTER_NODE_ID(i))
1154                 {
1155                         data0 = data;
1156                 }
1157                 else
1158                 {
1159                         if (data != data0)
1160                         {
1161                                 pool_error("pool_read_int: data does not match between between master(%x) slot[%d] (%x)",
1162                                                    data0, i, data);
1163                                 return -1;
1164                         }
1165                 }
1166         }
1167
1168         return data;
1169 }