]> git.8kb.co.uk Git - pgpool-ii/pgpool-ii_2.2.5/blob - pcp_child.c
Attempt to send a proper failure message to frontend when authentication
[pgpool-ii/pgpool-ii_2.2.5] / pcp_child.c
1 /* -*-pgsql-c-*- */
2 /*
3  * $Header: /cvsroot/pgpool/pgpool-II/pcp_child.c,v 1.11.2.1 2009/08/22 04:19:49 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  * pcp_child.c: PCP child process main
22  *
23  */
24 #include "config.h"
25
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <sys/un.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #ifdef HAVE_NETINET_TCP_H
33 #include <netinet/tcp.h>
34 #endif
35 #ifdef HAVE_SYS_SELECT_H
36 #include <sys/select.h>
37 #endif
38
39 #include <signal.h>
40
41 #include <stdio.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <sys/time.h>
47
48 #ifdef HAVE_FCNTL_H
49 #include <fcntl.h>
50 #endif
51
52 #include "pool.h"
53 #include "pcp/pcp_stream.h"
54 #include "pcp/pcp.h"
55 #include "md5.h"
56
57 #define MAX_FILE_LINE_LEN    512
58 #define MAX_USER_PASSWD_LEN  128
59
60 extern void pcp_set_timeout(long sec);
61 static int exit_request; /* non 0 means SIGTERM(smart shutdown) or SIGINT(fast shutdown) has arrived */
62
63 static RETSIGTYPE die(int sig);
64 static PCP_CONNECTION *pcp_do_accept(int unix_fd, int inet_fd);
65 static void unset_nonblock(int fd);
66 static int user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len);
67 static void pool_random_salt(char *md5Salt);
68 static RETSIGTYPE wakeup_handler(int sig);
69 static RETSIGTYPE reload_config_handler(int sig);
70
71 extern int myargc;
72 extern char **myargv;
73
74 static volatile sig_atomic_t pcp_got_sighup = 0;
75 volatile sig_atomic_t pcp_wakeup_request = 0;
76
77 void
78 pcp_do_child(int unix_fd, int inet_fd, char *pcp_conf_file)
79 {
80         PCP_CONNECTION *frontend = NULL;
81         int authenticated = 0;
82         struct timeval uptime;
83         char salt[4];
84         int random_salt = 0;
85         int i;
86         char tos;
87         int rsize;
88         char *buf = NULL;
89
90         pool_debug("I am PCP %d", getpid());
91
92         /* Identify myself via ps */
93         init_ps_display("", "", "", "");
94
95         gettimeofday(&uptime, NULL);
96         srandom((unsigned int) (getpid() ^ uptime.tv_usec));
97
98         /* set pcp_read() timeout */
99         pcp_set_timeout(pool_config->pcp_timeout);
100
101         /* set up signal handlers */
102         signal(SIGTERM, die);
103         signal(SIGINT, die);
104         signal(SIGHUP, reload_config_handler);
105         signal(SIGQUIT, die);
106         signal(SIGCHLD, SIG_DFL);
107         signal(SIGUSR1, SIG_DFL);
108         signal(SIGUSR2, wakeup_handler);
109         signal(SIGPIPE, SIG_IGN);
110         signal(SIGALRM, SIG_IGN);
111
112         for(;;)
113         {
114                 errno = 0;
115
116                 if (frontend == NULL)
117                 {
118                         frontend = pcp_do_accept(unix_fd, inet_fd);
119                         if (frontend == NULL)
120                                 continue;
121
122                         unset_nonblock(frontend->fd);
123                 }
124
125                 /* read a PCP packet */
126                 if (pcp_read(frontend, &tos, 1))
127                 {
128                         if (errorcode == TIMEOUTERR)
129                         {
130                                 pool_debug("pcp_child: pcp_read() has timed out");
131                                 authenticated = 0;
132                                 pcp_close(frontend); frontend = NULL;
133                                 free(buf); buf = NULL;
134                                 continue;
135                         }
136                         pool_error("pcp_child: pcp_read() failed. reason: %s", strerror(errno));
137                         exit(1);
138                 }
139                 if (pcp_read(frontend, &rsize, sizeof(int)))
140                 {
141                         if (errorcode == TIMEOUTERR)
142                         {
143                                 pool_debug("pcp_child: pcp_read() has timed out");
144                                 authenticated = 0;
145                                 pcp_close(frontend); frontend = NULL;
146                                 free(buf); buf = NULL;
147                                 continue;
148                         }
149                         pool_error("pcp_child: pcp_read() failed. reason: %s", strerror(errno));
150                         exit(1);
151                 }
152
153                 rsize = ntohl(rsize);
154                 if ((rsize - sizeof(int)) > 0)
155                 {
156                         buf = (char *)malloc(rsize - sizeof(int));
157                         if (buf == NULL)
158                         {
159                                 pool_error("pcp_child: malloc() failed. reason: %s", strerror(errno));
160                                 exit(1);
161                         }
162                         if (pcp_read(frontend, buf, rsize - sizeof(int)))
163                         {
164                                 if (errorcode == TIMEOUTERR)
165                                 {
166                                         pool_debug("pcp_child: pcp_read() has timed out");
167                                         authenticated = 0;
168                                         pcp_close(frontend); frontend = NULL;
169                                         free(buf); buf = NULL;
170                                         continue;
171                                 }
172                                 pool_error("pcp_child: pcp_read() failed. reason: %s", strerror(errno));
173                                 exit(1);
174                         }
175                 }
176
177                 /* is this connection authenticated? if not disconnect immediately*/
178                 if ((! authenticated) && (tos != 'R' && tos != 'M'))
179                 {
180                         pool_debug("pcp_child: connection not authorized");
181                         free(buf);
182                         buf = NULL;
183                         pcp_close(frontend);
184                         frontend = NULL;
185                         pool_signal(SIGALRM, SIG_IGN);
186                         continue;
187                 }
188
189                 /* process a request */
190                 pool_debug("pcp_child: received PCP packet type of service '%c'", tos);
191
192                 set_ps_display("PCP: processing a request", false);
193
194                 switch (tos)
195                 {
196                         case 'R':                       /* authentication */
197                         {
198                                 int wsize;
199
200                                 if (random_salt)
201                                 {
202                                         authenticated = user_authenticate(buf, pcp_conf_file, salt, 4);
203                                 }
204                                 if (!random_salt || !authenticated)
205                                 {
206                                         char code[] = "AuthenticationFailed";
207                                         char mesg[] = "username and/or password do not match";
208                                         pcp_write(frontend, "r", 1);
209                                         wsize = htonl(sizeof(code) + sizeof(mesg) + sizeof(int));
210                                         pcp_write(frontend, &wsize, sizeof(int));
211                                         pcp_write(frontend, code, sizeof(code));
212                                         pcp_write(frontend, mesg, sizeof(mesg));
213                                         if (pcp_flush(frontend) < 0)
214                                         {
215                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
216                                                 exit(1);
217                                         }
218
219                                         pool_error("pcp_child: authentication failed");
220                                         pcp_close(frontend);
221                                         frontend = NULL;
222                                         random_salt = 0;
223                                 }
224                                 else
225                                 {
226                                         char code[] = "AuthenticationOK";
227                                         pcp_write(frontend, "r", 1);
228                                         wsize = htonl(sizeof(code) + sizeof(int));
229                                         pcp_write(frontend, &wsize, sizeof(int));
230                                         pcp_write(frontend, code, sizeof(code));
231                                         if (pcp_flush(frontend) < 0)
232                                         {
233                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
234                                                 exit(1);
235                                         }
236                                         random_salt = 0;
237
238                                         pool_debug("pcp_child: authentication OK");
239                                 }
240                                 break;
241                         }
242
243                         case 'M':                       /* md5 salt */
244                         {
245                                 int wsize;
246
247                                 pool_random_salt(salt);
248                                 random_salt = 1;
249
250                                 pcp_write(frontend, "m", 1);
251                                 wsize = htonl(sizeof(int) + 4);
252                                 pcp_write(frontend, &wsize, sizeof(int));
253                                 pcp_write(frontend, salt, 4);
254                                 if (pcp_flush(frontend) < 0)
255                                 {
256                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
257                                         exit(1);
258                                 }
259
260                                 pool_debug("pcp_child: salt sent to the client");
261                                 break;
262                         }
263
264                         case 'L':                       /* node count */
265                         {
266                                 int wsize;
267                                 int node_count = pool_get_node_count();
268
269                                 char code[] = "CommandComplete";
270                                 char mesg[16];
271
272                                 snprintf(mesg, sizeof(mesg), "%d", node_count);
273
274                                 pcp_write(frontend, "l", 1);
275                                 wsize = htonl(sizeof(code) +
276                                                           strlen(mesg)+1 +
277                                                           sizeof(int));
278                                 pcp_write(frontend, &wsize, sizeof(int));
279                                 pcp_write(frontend, code, sizeof(code));
280                                 pcp_write(frontend, mesg, strlen(mesg)+1);
281                                 if (pcp_flush(frontend) < 0)
282                                 {
283                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
284                                         exit(1);
285                                 }
286
287                                 pool_debug("pcp_child: %d node(s) found", node_count);
288                                 break;
289                         }
290                         case 'I':                       /* node info */
291                         {
292                                 int node_id;
293                                 int wsize;
294
295                                 BackendInfo *bi = NULL;
296
297                                 node_id = atoi(buf);
298                                 bi = pool_get_node_info(node_id);
299
300                                 if (bi == NULL) {
301                                         char code[] = "Invalid Node ID";
302
303                                         pcp_write(frontend, "e", 1);
304                                         wsize = htonl(sizeof(code) + sizeof(int));
305                                         pcp_write(frontend, &wsize, sizeof(int));
306                                         pcp_write(frontend, code, sizeof(code));
307                                         if (pcp_flush(frontend) < 0)
308                                         {
309                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
310                                                 exit(1);
311                                         }
312
313                                         pool_debug("pcp_child: invalid node ID");
314                                 }
315                                 else
316                                 {
317                                         char code[] = "CommandComplete";
318                                         char port_str[6];
319                                         char status[2];
320                                         char weight_str[20];
321
322                                         snprintf(port_str, sizeof(port_str), "%d", bi->backend_port);
323                                         snprintf(status, sizeof(status), "%d", bi->backend_status);
324                                         snprintf(weight_str, sizeof(weight_str), "%f", bi->backend_weight);
325
326                                         pcp_write(frontend, "i", 1);
327                                         wsize = htonl(sizeof(code) +
328                                                                   strlen(bi->backend_hostname)+1 +
329                                                                   strlen(port_str)+1 +
330                                                                   strlen(status)+1 +
331                                                                   strlen(weight_str)+1 +
332                                                                   sizeof(int));
333                                         pcp_write(frontend, &wsize, sizeof(int));
334                                         pcp_write(frontend, code, sizeof(code));
335                                         pcp_write(frontend, bi->backend_hostname, strlen(bi->backend_hostname)+1);
336                                         pcp_write(frontend, port_str, strlen(port_str)+1);
337                                         pcp_write(frontend, status, strlen(status)+1);
338                                         pcp_write(frontend, weight_str, strlen(weight_str)+1);
339                                         if (pcp_flush(frontend) < 0)
340                                         {
341                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
342                                                 exit(1);
343                                         }
344
345                                         pool_debug("pcp_child: retrieved node information from shared memory");
346                                 }
347                                 break;
348                         }
349
350                         case 'N':                       /* process count */
351                         {
352                                 int wsize;
353                                 int process_count;
354                                 char process_count_str[16];
355                                 int *process_list = NULL;
356                                 char code[] = "CommandComplete";
357                                 char *mesg = NULL;
358                                 int i;
359                                 int total_port_len = 0;
360
361                                 process_list = pool_get_process_list(&process_count);
362
363                                 mesg = (char *)malloc(6*process_count); /* port# is at most 5 characters long (MAX:65535) */
364                                 if (mesg == NULL)
365                                 {
366                                         pool_error("pcp_child: malloc() failed. reason: %s", strerror(errno));
367                                         exit(1);
368                                 }
369
370                                 snprintf(process_count_str, sizeof(process_count_str), "%d", process_count);
371
372                                 for (i = 0; i < process_count; i++)
373                                 {
374                                         char port[6];
375                                         snprintf(port, sizeof(port), "%d", process_list[i]);
376                                         snprintf(mesg+total_port_len, strlen(port)+1, "%s", port);
377                                         total_port_len += strlen(port)+1;
378                                 }
379
380                                 pcp_write(frontend, "n", 1);
381                                 wsize = htonl(sizeof(code) +
382                                                           strlen(process_count_str)+1 +
383                                                           total_port_len +
384                                                           sizeof(int));
385                                 pcp_write(frontend, &wsize, sizeof(int));
386                                 pcp_write(frontend, code, sizeof(code));
387                                 pcp_write(frontend, process_count_str, strlen(process_count_str)+1);
388                                 pcp_write(frontend, mesg, total_port_len);
389                                 if (pcp_flush(frontend) < 0)
390                                 {
391                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
392                                         exit(1);
393                                 }
394
395                                 free(process_list);
396                                 free(mesg);
397
398                                 pool_debug("pcp_child: %d process(es) found", process_count);
399                                 break;
400                         }
401
402                         case 'P':                       /* process info */
403                         {
404                                 int proc_id;
405                                 int wsize;
406
407                                 ProcessInfo *pi = NULL;
408
409                                 proc_id = atoi(buf);
410                                 pi = pool_get_process_info(proc_id);
411
412                                 if (pi == NULL)
413                                 {
414                                         char code[] = "InvalidProcessID";
415
416                                         pcp_write(frontend, "e", 1);
417                                         wsize = htonl(sizeof(code) + sizeof(int));
418                                         pcp_write(frontend, &wsize, sizeof(int));
419                                         pcp_write(frontend, code, sizeof(code));
420                                         if (pcp_flush(frontend) < 0)
421                                         {
422                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
423                                                 exit(1);
424                                         }
425
426                                         pool_debug("pcp_child: invalid process ID");
427                                 }
428                                 else
429                                 {
430                                         /* First, send array size of connection_info */
431                                         char arr_code[] = "ArraySize";
432                                         char con_info_size[16];
433                                         /* Finally, indicate that all data is sent */
434                                         char fin_code[] = "CommandComplete";
435
436                                         snprintf(con_info_size, sizeof(con_info_size), "%d", pool_config->max_pool);
437
438                                         pcp_write(frontend, "p", 1);
439                                         wsize = htonl(sizeof(arr_code) +
440                                                                   strlen(con_info_size)+1 +
441                                                                   sizeof(int));
442                                         pcp_write(frontend, &wsize, sizeof(int));
443                                         pcp_write(frontend, arr_code, sizeof(arr_code));
444                                         pcp_write(frontend, con_info_size, strlen(con_info_size)+1);
445                                         if (pcp_flush(frontend) < 0)
446                                         {
447                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
448                                                 exit(1);
449                                         }
450
451                                         /* Second, send process information for all connection_info */
452
453                                         for (i = 0; i < pool_config->max_pool; i++)
454                                         {
455                                                 char code[] = "ProcessInfo";
456                                                 char proc_start_time[20];
457                                                 char proc_create_time[20];
458                                                 char majorversion[5];
459                                                 char minorversion[5];
460                                                 char pool_counter[16];
461
462                                                 snprintf(proc_start_time, sizeof(proc_start_time), "%ld", pi->start_time);
463                                                 snprintf(proc_create_time, sizeof(proc_create_time), "%ld", pi->connection_info[i].create_time);
464                                                 snprintf(majorversion, sizeof(majorversion), "%d", pi->connection_info[i].major);
465                                                 snprintf(minorversion, sizeof(minorversion), "%d", pi->connection_info[i].minor);
466                                                 snprintf(pool_counter, sizeof(pool_counter), "%d", pi->connection_info[i].counter);
467
468                                                 pcp_write(frontend, "p", 1);
469                                                 wsize = htonl(sizeof(code) +
470                                                                           strlen(pi->connection_info[i].database)+1 +
471                                                                           strlen(pi->connection_info[i].user)+1 +
472                                                                           strlen(proc_start_time)+1 +
473                                                                           strlen(proc_create_time)+1 +
474                                                                           strlen(majorversion)+1 +
475                                                                           strlen(minorversion)+1 +
476                                                                           strlen(pool_counter)+1 +
477                                                                           sizeof(int));
478                                                 pcp_write(frontend, &wsize, sizeof(int));
479                                                 pcp_write(frontend, code, sizeof(code));
480                                                 pcp_write(frontend, pi->connection_info[i].database, strlen(pi->connection_info[i].database)+1);
481                                                 pcp_write(frontend, pi->connection_info[i].user, strlen(pi->connection_info[i].user)+1);
482                                                 pcp_write(frontend, proc_start_time, strlen(proc_start_time)+1);
483                                                 pcp_write(frontend, proc_create_time, strlen(proc_create_time)+1);
484                                                 pcp_write(frontend, majorversion, strlen(majorversion)+1);
485                                                 pcp_write(frontend, minorversion, strlen(minorversion)+1);
486                                                 pcp_write(frontend, pool_counter, strlen(pool_counter)+1);
487                                                 if (pcp_flush(frontend) < 0)
488                                                 {
489                                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
490                                                         exit(1);
491                                                 }
492                                         }
493
494                                         pcp_write(frontend, "p", 1);
495                                         wsize = htonl(sizeof(fin_code) +
496                                                                   sizeof(int));
497                                         pcp_write(frontend, &wsize, sizeof(int));
498                                         pcp_write(frontend, fin_code, sizeof(fin_code));
499                                         if (pcp_flush(frontend) < 0)
500                                         {
501                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
502                                                 exit(1);
503                                         }
504
505                                         pool_debug("pcp_child: retrieved process information from shared memory");
506                                 }
507                                 break;
508                         }
509
510                         case 'S':                       /* SystemDB info */
511                         {
512                                 int wsize;
513
514                                 SystemDBInfo *si = NULL;
515                                 si = pool_get_system_db_info();
516
517                                 /* since PCP clients can only see SystemDBInfo, set system_db_status from the shared memory */
518                                 si->system_db_status = SYSDB_STATUS;
519
520                                 if (si == NULL)
521                                 {
522                                         char code[] = "SystemDBNotDefined";
523
524                                         pcp_write(frontend, "e", 1);
525                                         wsize = htonl(sizeof(code) + sizeof(int));
526                                         pcp_write(frontend, &wsize, sizeof(int));
527                                         pcp_write(frontend, code, sizeof(code));
528                                         if (pcp_flush(frontend) < 0)
529                                         {
530                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
531                                                 exit(1);
532                                         }
533                                 }
534                                 else
535                                 {
536                                         /* first, send systemDB information */
537                                         char code[] = "SystemDBInfo";
538                                         char port[6];
539                                         char status[2];
540                                         char dist_def_num[16];
541                                         /* finally, indicate that all data is sent */
542                                         char fin_code[] = "CommandComplete";
543
544                                         snprintf(port, sizeof(port), "%d", si->port);
545                                         snprintf(status, sizeof(status), "%d", si->system_db_status);
546                                         snprintf(dist_def_num, sizeof(dist_def_num), "%d", si->dist_def_num);
547
548                                         pcp_write(frontend, "s", 1);
549                                         wsize = htonl(sizeof(code) +
550                                                                   strlen(si->hostname)+1 +
551                                                                   strlen(port)+1 +
552                                                                   strlen(si->user)+1 +
553                                                                   strlen(si->password)+1 +
554                                                                   strlen(si->schema_name)+1 +
555                                                                   strlen(si->database_name)+1 +
556                                                                   strlen(dist_def_num)+1 +
557                                                                   strlen(status)+1 +
558                                                                   sizeof(int));
559                                         pcp_write(frontend, &wsize, sizeof(int));
560                                         pcp_write(frontend, code, sizeof(code));
561                                         pcp_write(frontend, si->hostname, strlen(si->hostname)+1);
562                                         pcp_write(frontend, port, strlen(port)+1);
563                                         pcp_write(frontend, si->user, strlen(si->user)+1);
564                                         pcp_write(frontend, si->password, strlen(si->password)+1);
565                                         pcp_write(frontend, si->schema_name, strlen(si->schema_name)+1);
566                                         pcp_write(frontend, si->database_name, strlen(si->database_name)+1);
567                                         pcp_write(frontend, dist_def_num, strlen(dist_def_num)+1);
568                                         pcp_write(frontend, status, strlen(status)+1);
569                                         if (pcp_flush(frontend) < 0)
570                                         {
571                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
572                                                 exit(1);
573                                         }
574
575                                         /* second, send DistDefInfo if any */
576                                         if (si->dist_def_num > 0)
577                                         {
578                                                 char dist_code[] = "DistDefInfo";
579                                                 char col_num[16];
580                                                 int col_list_total_len;
581                                                 int type_list_total_len;
582                                                 char *col_list = NULL;
583                                                 char *type_list = NULL;
584                                                 int col_list_offset;
585                                                 int type_list_offset;
586                                                 DistDefInfo *ddi;
587                                                 int i, j;
588
589                                                 for (i = 0; i < si->dist_def_num; i++)
590                                                 {
591                                                         ddi = &si->dist_def_slot[i];
592                                                         snprintf(col_num, sizeof(col_num), "%d", ddi->col_num);
593
594                                                         col_list_total_len = type_list_total_len = 0;
595                                                         for (j = 0; j < ddi->col_num; j++)
596                                                         {
597                                                                 col_list_total_len += strlen(ddi->col_list[j]) + 1;
598                                                                 type_list_total_len += strlen(ddi->type_list[j]) + 1;
599                                                         }
600
601                                                         col_list = (char *)malloc(col_list_total_len);
602                                                         type_list = (char *)malloc(type_list_total_len);
603                                                         if (col_list == NULL || type_list == NULL)
604                                                         {
605                                                                 pool_error("pcp_child: malloc() failed. reason: %s", strerror(errno));
606                                                                 exit(1);
607                                                         }
608
609                                                         col_list_offset = type_list_offset = 0;
610                                                         for (j = 0; j < ddi->col_num; j++)
611                                                         {
612                                                                 snprintf(col_list + col_list_offset, strlen(ddi->col_list[j])+1,
613                                                                                  "%s", ddi->col_list[j]);
614                                                                 snprintf(type_list + type_list_offset, strlen(ddi->type_list[j])+1,
615                                                                                  "%s", ddi->type_list[j]);
616                                                                 col_list_offset += strlen(ddi->col_list[j]) + 1;
617                                                                 type_list_offset += strlen(ddi->type_list[j]) + 1;
618                                                         }
619
620                                                         pcp_write(frontend, "s", 1);
621                                                         wsize = htonl(sizeof(dist_code) +
622                                                                                   strlen(ddi->dbname)+1 +
623                                                                                   strlen(ddi->schema_name)+1 +
624                                                                                   strlen(ddi->table_name)+1 +
625                                                                                   strlen(ddi->dist_key_col_name)+1 +
626                                                                                   strlen(col_num)+1 +
627                                                                                   col_list_total_len +
628                                                                                   type_list_total_len +
629                                                                                   strlen(ddi->dist_def_func)+1 +
630                                                                                   sizeof(int));
631                                                         pcp_write(frontend, &wsize, sizeof(int));
632                                                         pcp_write(frontend, dist_code, sizeof(dist_code));
633                                                         pcp_write(frontend, ddi->dbname, strlen(ddi->dbname)+1);
634                                                         pcp_write(frontend, ddi->schema_name, strlen(ddi->schema_name)+1);
635                                                         pcp_write(frontend, ddi->table_name, strlen(ddi->table_name)+1);
636                                                         pcp_write(frontend, ddi->dist_key_col_name, strlen(ddi->dist_key_col_name)+1);
637                                                         pcp_write(frontend, col_num, strlen(col_num)+1);
638                                                         pcp_write(frontend, col_list, col_list_total_len);
639                                                         pcp_write(frontend, type_list, type_list_total_len);
640                                                         pcp_write(frontend, ddi->dist_def_func, strlen(ddi->dist_def_func)+1);
641                                                         if (pcp_flush(frontend) < 0)
642                                                         {
643                                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
644                                                                 exit(1);
645                                                         }
646
647                                                         free(col_list);
648                                                         free(type_list);
649                                                 }
650                                         }
651
652                                         pcp_write(frontend, "s", 1);
653                                         wsize = htonl(sizeof(fin_code) +
654                                                                   sizeof(int));
655                                         pcp_write(frontend, &wsize, sizeof(int));
656                                         pcp_write(frontend, fin_code, sizeof(fin_code));
657                                         if (pcp_flush(frontend) < 0)
658                                         {
659                                                 pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
660                                                 exit(1);
661                                         }
662
663                                         pool_debug("pcp_child: retrieved SystemDB information from shared memory");
664                                 }
665                                 break;
666                         }
667
668                         case 'D':                       /* detach node */
669                         {
670                                 int node_id;
671                                 int wsize;
672                                 char code[] = "CommandComplete";
673
674                                 node_id = atoi(buf);
675                                 pool_debug("pcp_child: detaching Node ID %d", node_id);
676                                 notice_backend_error(node_id);
677
678                                 pcp_write(frontend, "d", 1);
679                                 wsize = htonl(sizeof(code) + sizeof(int));
680                                 pcp_write(frontend, &wsize, sizeof(int));
681                                 pcp_write(frontend, code, sizeof(code));
682                                 if (pcp_flush(frontend) < 0)
683                                 {
684                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
685                                         exit(1);
686                                 }
687                                 break;
688                         }
689
690                         case 'C':                       /* attach node */
691                         {
692                                 int node_id;
693                                 int wsize;
694                                 char code[] = "CommandComplete";
695
696                                 node_id = atoi(buf);
697                                 pool_debug("pcp_child: attaching Node ID %d", node_id);
698                                 send_failback_request(node_id);
699
700                                 pcp_write(frontend, "c", 1);
701                                 wsize = htonl(sizeof(code) + sizeof(int));
702                                 pcp_write(frontend, &wsize, sizeof(int));
703                                 pcp_write(frontend, code, sizeof(code));
704                                 if (pcp_flush(frontend) < 0)
705                                 {
706                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
707                                         exit(1);
708                                 }
709                                 break;
710                         }
711
712                         case 'T':
713                         {
714                                 char mode = buf[0];
715                                 pid_t ppid = getppid();
716
717                                 if (mode == 's')
718                                 {
719                                         pool_debug("pcp_child: sending SIGTERM to the parent process(%d)", ppid);
720                                         kill(ppid, SIGTERM);
721                                 }
722                                 else if (mode == 'f')
723                                 {
724                                         pool_debug("pcp_child: sending SIGINT to the parent process(%d)", ppid);
725                                         kill(ppid, SIGINT);
726                                 }
727                                 else if (mode == 'i')
728                                 {
729                                         pool_debug("pcp_child: sending SIGQUIT to the parent process(%d)", ppid);
730                                         kill(ppid, SIGQUIT);
731                                 }
732                                 else
733                                 {
734                                         pool_debug("pcp_child: invalid shutdown mode %c", mode);
735                                 }
736
737                                 break;
738                         }
739
740                         case 'O': /* recovery request */
741                         {
742                                 int node_id;
743                                 int wsize;
744                                 char code[] = "CommandComplete";
745                                 int r;
746
747                                 if (!REPLICATION)
748                                 {
749                                         int len = strlen("recovery request is accepted only in replication mode. ") + 1;
750                                         pcp_write(frontend, "e", 1);
751                                         wsize = htonl(sizeof(int) + len);
752                                         pcp_write(frontend, &wsize, sizeof(int));
753                                         pcp_write(frontend, "recovery request is accepted only in replication mode. ", len);
754                                 }
755                                 else
756                                 {
757                                         pool_debug("pcp_child: start online recovery");
758                                         node_id = atoi(buf);
759
760                                         r = start_recovery(node_id);
761                                         finish_recovery();
762
763                                         if (r == 0) /* success */
764                                         {
765                                                 pcp_write(frontend, "c", 1);
766                                                 wsize = htonl(sizeof(code) + sizeof(int));
767                                                 pcp_write(frontend, &wsize, sizeof(int));
768                                                 pcp_write(frontend, code, sizeof(code));
769                                         }
770                                         else
771                                         {
772                                                 int len = strlen("recovery failed") + 1;
773                                                 pcp_write(frontend, "e", 1);
774                                                 wsize = htonl(sizeof(int) + len);
775                                                 pcp_write(frontend, &wsize, sizeof(int));
776                                                 pcp_write(frontend, "recovery failed", len);
777                                         }
778                                 }
779                                 if (pcp_flush(frontend) < 0)
780                                 {
781                                         pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
782                                         exit(1);
783                                 }
784                         }
785                                 break;
786
787                         case 'F':
788                                 pool_debug("pcp_child: stop online recovery");
789                                 break;
790
791                         case 'X':                       /* disconnect */
792                                 pool_debug("pcp_child: client disconnecting. close connection");
793                                 authenticated = 0;
794                                 pcp_close(frontend);
795                                 frontend = NULL;
796                                 break;
797
798                         default:
799                                 pool_error("pcp_child: unknown packet type %c received", tos);
800                                 exit(1);
801                 }
802
803                 free(buf);
804                 buf = NULL;
805
806                 /* seems ok. cancel idle check timer */
807                 pool_signal(SIGALRM, SIG_IGN);
808         }
809
810         exit(0);
811 }
812
813 static RETSIGTYPE
814 die(int sig)
815 {
816         exit_request = 1;
817
818         pool_debug("PCP child receives shutdown request signal %d", sig);
819
820         switch (sig)
821         {
822                 case SIGTERM:   /* smart shutdown */
823                 case SIGINT:    /* fast shutdown */
824                 case SIGQUIT:   /* immediate shutdown */
825                         exit(0);
826                         break;
827                 default:
828                         break;
829         }
830
831         /* send_frontend_exits(); */
832
833         exit(0);
834 }
835
836 static RETSIGTYPE
837 wakeup_handler(int sig)
838 {
839         pcp_wakeup_request = 1;
840 }
841
842 static PCP_CONNECTION *
843 pcp_do_accept(int unix_fd, int inet_fd)
844 {
845         PCP_CONNECTION *pc = NULL;
846
847         fd_set readmask;
848         int fds;
849
850         struct sockaddr addr;
851         socklen_t addrlen;
852         int fd = 0;
853         int afd;
854         int inet = 0;
855
856         set_ps_display("PCP: wait for connection request", false);
857
858         FD_ZERO(&readmask);
859         FD_SET(unix_fd, &readmask);
860         if (inet_fd)
861                 FD_SET(inet_fd, &readmask);
862
863         fds = select(Max(unix_fd, inet_fd)+1, &readmask, NULL, NULL, NULL);
864
865         if (fds == -1)
866         {
867                 if (errno == EAGAIN || errno == EINTR)
868                         return NULL;
869
870                 pool_error("pcp_child: select() failed. reason: %s", strerror(errno));
871                 return NULL;
872         }
873
874         if (FD_ISSET(unix_fd, &readmask))
875         {
876                 fd = unix_fd;
877         }
878
879         if (FD_ISSET(inet_fd, &readmask))
880         {
881                 fd = inet_fd;
882                 inet++;
883         }
884
885         addrlen = sizeof(addr);
886
887         afd = accept(fd, &addr, &addrlen);
888         if (afd < 0)
889         {
890                 /*
891                  * "Resource temporarily unavailable" (EAGAIN or EWOULDBLOCK)
892                  * can be silently ignored.
893                  */
894                 if (errno != EAGAIN && errno != EWOULDBLOCK)
895                         pool_error("pcp_child: accept() failed. reason: %s", strerror(errno));
896                 return NULL;
897         }
898
899         if (pcp_got_sighup)
900         {
901                 pool_get_config(get_config_file_name(), RELOAD_CONFIG);
902                 pcp_got_sighup = 0;
903         }
904
905         pool_debug("I am PCP %d accept fd %d", getpid(), afd);
906
907         if (inet)
908         {
909                 int on = 1;
910
911                 if (setsockopt(afd, IPPROTO_TCP, TCP_NODELAY,
912                                            (char *) &on,
913                                            sizeof(on)) < 0)
914                 {
915                         pool_error("pcp_child: setsockopt() failed: %s", strerror(errno));
916                         close(afd);
917                         return NULL;
918                 }
919                 if (setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE,
920                                            (char *) &on,
921                                            sizeof(on)) < 0)
922                 {
923                         pool_error("pcp_child: setsockopt() failed: %s", strerror(errno));
924                         close(afd);
925                         return NULL;
926                 }
927         }
928
929         if ((pc = pcp_open(afd)) == NULL)
930         {
931                 close(afd);
932                 return NULL;
933         }
934         return pc;
935 }
936
937 /*
938  * unset non-block flag
939  */
940 static void
941 unset_nonblock(int fd)
942 {
943         int var;
944
945         /* set fd to non-blocking */
946         var = fcntl(fd, F_GETFL, 0);
947         if (var == -1)
948         {
949                 pool_error("pcp_child: fcntl failed. %s", strerror(errno));
950                 exit(1);
951         }
952         if (fcntl(fd, F_SETFL, var & ~O_NONBLOCK) == -1)
953         {
954                 pool_error("pcp_child: fcntl failed. %s", strerror(errno));
955                 exit(1);
956         }
957 }
958
959 /*
960  * see if received username and password matches with one in the file
961  */
962 static int
963 user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len)
964 {
965         FILE *fp = NULL;
966         char packet_username[MAX_USER_PASSWD_LEN+1];
967         char packet_password[MAX_USER_PASSWD_LEN+1];
968         char encrypt_buf[(MD5_PASSWD_LEN+1)*2];
969         char file_username[MAX_USER_PASSWD_LEN+1];
970         char file_password[MD5_PASSWD_LEN+1];
971         char *index = NULL;
972         static char line[MAX_FILE_LINE_LEN+1];
973         int i, len;
974
975         /* strcpy() should be OK, but use strncpy() to be extra careful */
976         strncpy(packet_username, buf, MAX_USER_PASSWD_LEN);
977         index = (char *) memchr(buf, '\0', MAX_USER_PASSWD_LEN) + 1;
978         if (index == NULL)
979         {
980                 pool_debug("pcp_child: error while reading authentication packet");
981                 return 0;
982         }
983         strncpy(packet_password, index, MAX_USER_PASSWD_LEN);
984
985         fp = fopen(passwd_file, "r");
986         if (fp == NULL)
987         {
988                 pool_error("pcp_child: could not open %s. reason: %s", passwd_file, strerror(errno));
989                 return 0;
990         }
991
992         /* for now, I don't care if duplicate username exists in the config file */
993         while ((fgets(line, MAX_FILE_LINE_LEN, fp)) != NULL)
994         {
995                 i = 0;
996                 len = 0;
997
998                 if (line[0] == '\n')
999                         continue;
1000                 if (line[0] == '#')
1001                         continue;
1002
1003                 while (line[i] != ':')
1004                 {
1005                         len++;
1006                         if (++i > MAX_USER_PASSWD_LEN)
1007                         {
1008                                 pool_error("pcp_child: user name in %s exceeds %d", passwd_file, MAX_USER_PASSWD_LEN);
1009                                 fclose(fp);
1010                                 return 0;
1011                         }
1012                 }
1013                 memcpy(file_username, line, len);
1014                 file_username[len] = '\0';
1015
1016                 if (strcmp(packet_username, file_username) != 0)
1017                         continue;
1018
1019                 i++;
1020                 len = 0;
1021                 while (line[i] != '\n' && line[i] != '\0')
1022                 {
1023                         len++;
1024                         if (++i > MAX_USER_PASSWD_LEN)
1025                         {
1026                                 pool_error("pcp_child: password in %s exceeds %d", passwd_file, MAX_USER_PASSWD_LEN);
1027                                 fclose(fp);
1028                                 return 0;
1029                         }
1030                 }
1031
1032                 memcpy(file_password, line+strlen(file_username)+1, len);
1033                 file_password[len] = '\0';
1034
1035                 pool_md5_encrypt(file_password, file_username, strlen(file_username),
1036                                           encrypt_buf + MD5_PASSWD_LEN + 1);
1037                 encrypt_buf[(MD5_PASSWD_LEN+1)*2-1] = '\0';
1038
1039                 pool_md5_encrypt(encrypt_buf+MD5_PASSWD_LEN+1, salt, salt_len,
1040                                           encrypt_buf);
1041                 encrypt_buf[MD5_PASSWD_LEN] = '\0';
1042
1043                 if (strcmp(encrypt_buf, packet_password) == 0)
1044                 {
1045                         fclose(fp);
1046                         return 1;
1047                 }
1048         }
1049
1050         fclose(fp);
1051         return 0;
1052 }
1053
1054 /*
1055  *  pool_random_salt
1056  */
1057 static void pool_random_salt(char *md5Salt)
1058 {
1059         long rand = random();
1060
1061         md5Salt[0] = (rand % 255) + 1;
1062         rand = random();
1063         md5Salt[1] = (rand % 255) + 1;
1064         rand = random();
1065         md5Salt[2] = (rand % 255) + 1;
1066         rand = random();
1067         md5Salt[3] = (rand % 255) + 1;
1068 }
1069
1070 /* SIGHUP handler */
1071 static RETSIGTYPE reload_config_handler(int sig)
1072 {
1073         pcp_got_sighup = 1;
1074 }