pgpool2.git / summary / log / commit / refs

commit    88fdc5f2f2df98b1c6b5e8785924c6a3eabd1aed
Author:   Muhammad Usama <m.usama@gmail.com>
Date:     Fri Dec 25 19:53:49 2015 +0000

    Adding the mechanism to authenticate the watchdog IPC commands.
    
    For the authentication purpose, the existing wd_authkey pgpool-II configuration
    parameter is used. All clients communicating with pgpool-II watchdog process
    needs to provide wd_authkey value for "IPCAuthKey" key in the JSON data of the
    command.. Since the IPC is meant for communication between internal pgpool-II
    processes and with external processes on the same machine, so instead of
    calculating the hash and inventing a more complicated process of IPC
    authentication, the simple wd_authkey matching is used to validate the clients.
    And when the wd_authkey is not provided by the user in pgpool.conf than the
    watchdog IPC authentication is disabled.
    
    The commit also takes care of second related problem in the watchdog IPC system.
    Since there are some functions visible over the watchdog IPC channel, we want to
    restrict to the outer world. Like for example the interlocking command functions
    and node failover related functions. So for these restricted functions, a new
    shared key mechanism is created, This random value is initialized by watchdog at
    startup and placed in the shared memory
    (accessible only to  pgpool-II internal processes), And the execution of all these
    restricted functions is only allowed if that shared key value is provided by the
    caller in the function's JSON data. Since the shared key value is only visible
    to local pgpool-II processes, so the technique ensures that only local pgpool-II
    process can execute the restricted functions.


doc/pgpool-en.html | 36 +++--- src/auth/pool_auth.c | 1 + src/include/watchdog/wd_ipc_commands.h | 4 +- src/include/watchdog/wd_ipc_defines.h | 11 ++ src/include/watchdog/wd_json_data.h | 5 +- src/watchdog/watchdog.c | 207 +++++++++++++++++++++++++++++++-- src/watchdog/wd_commands.c | 74 +++++++++--- src/watchdog/wd_json_data.c | 27 ++++- src/watchdog/wd_lifecheck.c | 2 +- 9 files changed, 321 insertions(+), 46 deletions(-) diff --git a/doc/pgpool-en.html b/doc/pgpool-en.html index 684970979..7190a44be 100644 --- a/doc/pgpool-en.html +++ b/doc/pgpool-en.html @@ -4100,7 +4100,12 @@ All following options are required to be specified in watchdog process. All the pgpool-II must have the same key. Packets from watchdog of wrong key will be rejects. This authentication is applied also for heatrbeat singals if lifecheck method is heartbeat mode. - If this is empty (default), watchdog doesn't conduct authenticate. + </p><p> + Since pgpool-II <span class="version">V3.5 -</span> wd_authkey is also used to authenticate the watchdog IPC clients. + All clients communicating with pgpool-II watchdog process needs to provide this + wd_authkey value for "IPCAuthKey" key in the JSON data of the command. + </p><p> + If this is empty (default), watchdog IPC and watchdog cluster authentication is disabled. </p> <p> You need to restart pgpool-II if you change this value. @@ -4564,30 +4569,32 @@ as the command or command result type. The below table lists all valid types and </p> <table border> <tr class="header"><th>Name</th> <th>Byte Value</th> <th>Type</th><th>Description</th></tr> - <tr><th>Register for notifications</th> <td>'0'</td> <td>Command packet</td> <td>Command to register the current connection to receive watchdog notifications</td></tr> - <tr><th>Node status change</th> <td>'2'</td> <td>Command packet</td> <td>Command to inform watchdog about node status change of watchddog node</td></tr> - <tr><th>Get nodes list</th> <td>'3'</td> <td>Command packet</td> <td>Command to get the list of all configured watchdog nodes</td></tr> - <tr><th>Nodes list data</th> <td>'4'</td> <td>Result packet</td> <td>The JSON data in packet + <tr><th><a name="ipc_reg_for_notifications"></a>REGISTER FOR NOTIFICATIONS</th> <td>'0'</td> <td>Command packet</td> <td>Command to register the current connection to receive watchdog notifications</td></tr> + <tr><th><a name="ipc_node_status_change"></a>NODE STATUS CHANGE</th> <td>'2'</td> <td>Command packet</td> <td>Command to inform watchdog about node status change of watchddog node</td></tr> + <tr><th><a name="ipc_get_nodes_list"></a>GET NODES LIST</h4></th> <td>'3'</td> <td>Command packet</td> <td>Command to get the list of all configured watchdog nodes</td></tr> + <tr><th><a name="ipc_nodes_list_data"></a>NODES LIST DATA</th> <td>'4'</td> <td>Result packet</td> <td>The JSON data in packet contains the list of all configured watchdog nodes</th></tr> - <tr><th>Cluster in transition</th> <td>'7'</td> <td>Result packet</td> <td>Watchdog returns this packet type when it is not possible to process the command because the cluster is transitioning.'</td></tr> - <tr><th>Result BAD</th> <td>'8'</td> <td>Result packet</td> <td>Watchdog returns this packet type when the IPC command fails</td></tr> - <tr><th>Result OK</th> <td>'9'</td> <td>Result packet</td> <td>Watchdog returns this packet type when IPC command succeeds</td></tr> + <tr><th><a name="ipc_cluster_in_tran"></a>CLUSTER IN TRANSITION</th> <td>'7'</td> <td>Result packet</td> <td>Watchdog returns this packet type when it is not possible to process the command because the cluster is transitioning.'</td></tr> + <tr><th><a name="ipc_result_bad"></a>RESULT BAD</th> <td>'8'</td> <td>Result packet</td> <td>Watchdog returns this packet type when the IPC command fails</td></tr> + <tr><th><a name="ipc_result_ok"></a>RESULT OK</th> <td>'9'</td> <td>Result packet</td> <td>Watchdog returns this packet type when IPC command succeeds</td></tr> </table> </dl> <h3 id="external_lifecheck_ipc">External lifecheck IPC packets and data</h3> <dl> -"Get nodes list('3')", "Nodes list data('4')" and "Node status change('2')" IPC messages of watchdog can be used to integration an external lifecheck systems. +<a href="#ipc_get_nodes_list">"GET NODES LIST"</a> ,<a href="#ipc_nodes_list_data">"NODES LIST DATA"</a> +and <a href="#ipc_node_status_change">"NODE STATUS CHANGE"</a> IPC messages of watchdog can be used to integration an external lifecheck systems. Note that the built-in lifecheck of pgpool also uses the same channel and technique. <h4 id="external_lifecheck_ipc">Getting list of configured watchdog nodes</h4> <dl> -Any third party lifecheck system can send the "Get nodes list('3')" type packet on watchdog IPC socket with a zero length data to get the "Nodes list data('4')" -type result packet which, contains the list of all configured watchdog nodes to health check on in JSON format. -The Json of watchdog nodes contains the "WatchdogNodes" Array of all watchdog nodes. Each watchdog json node contains the +Any third party lifecheck system can send the <a href="#ipc_get_nodes_list">"GET NODES LIST"</a> packet on watchdog IPC socket with a JSON data containing the authorization key and value if +<a href="#WD_AUTHKEY">wd_authkey</a> is set or empty packet data when wd_authkey is not set to get the <a href="#ipc_nodes_list_data">"NODES LIST DATA"</a> result packet which, contains the list of all configured +watchdog nodes to health check on in JSON format. +The JSON of watchdog nodes contains the "WatchdogNodes" Array of all watchdog nodes. Each watchdog JSON node contains "ID", "NodeName", "HostName", "DelegateIP", "WdPort" and "PgpoolPort" for each node. <pre> --- The example JSON data contained in "Nodes list data('4')" +-- The example JSON data contained in <a href="#ipc_nodes_list_data">"NODES LIST DATA"</a> { "NodeCount":3, @@ -4628,7 +4635,7 @@ The Json of watchdog nodes contains the "WatchdogNodes" Array of all watchdog no After getting the configured watchdog nodes information from the watchdog the external lifecheck system can proceed with health checking of watchdog nodes, and when it detects some status change of any node it can inform that to watchdog -using the "Node status change('2')" IPC messages of watchdog. +using the <a href="#ipc_node_status_change">"NODE STATUS CHANGE"</a> IPC messages of watchdog. The data in the message should contain the JSON with the node ID of the node whose status is changed (The node ID must be same as returned by watchdog for that node in WatchdogNodes list) and the new status of node. <pre> @@ -4639,6 +4646,7 @@ failed on node with ID 1 will look like "NodeID":1, "NodeStatus":1, "Message":"optional message string to log by watchdog for this event" + "IPCAuthKey":"<a href="#WD_AUTHKEY">wd_authkey</a> configuration parameter value" } -- NodeStatus values meanings are as follows diff --git a/src/auth/pool_auth.c b/src/auth/pool_auth.c index e165521d9..597d56bdf 100644 --- a/src/auth/pool_auth.c +++ b/src/auth/pool_auth.c @@ -1275,6 +1275,7 @@ int pool_read_int(POOL_CONNECTION_POOL *cp) */ void pool_random_salt(char *md5Salt) { + srandom(time(NULL)); long rand = random(); md5Salt[0] = (rand % 255) + 1; diff --git a/src/include/watchdog/wd_ipc_commands.h b/src/include/watchdog/wd_ipc_commands.h index 2e969c30e..9dcc602a9 100644 --- a/src/include/watchdog/wd_ipc_commands.h +++ b/src/include/watchdog/wd_ipc_commands.h @@ -7,7 +7,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2012 PgPool Global Development Group + * Copyright (c) 2003-2015 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -45,6 +45,8 @@ typedef struct WDIPCCmdResult extern void wd_ipc_initialize_data(void); extern char* get_watchdog_ipc_address(void); +extern unsigned int* get_ipc_shared_key(void); + extern int wd_set_node_mask_for_failback_req(int *node_id_set, int count); extern int wd_set_node_mask_for_degenerate_req(int *node_id_set, int count); diff --git a/src/include/watchdog/wd_ipc_defines.h b/src/include/watchdog/wd_ipc_defines.h index 9e3277f13..ca16bc701 100644 --- a/src/include/watchdog/wd_ipc_defines.h +++ b/src/include/watchdog/wd_ipc_defines.h @@ -70,6 +70,17 @@ typedef enum WDFailoverCMDResults #define WD_FUNCTION_DEGENERATE_REQUEST "DEGENERATE_BACKEND_REQUEST" #define WD_FUNCTION_PROMOTE_REQUEST "PROMOTE_BACKEND_REQUEST" +#define WD_IPC_AUTH_KEY "IPCAuthKey" /* JSON data key for authentication. + * watchdog IPC server use the value for this key + * to authenticate the external IPC clients + * The valid value for this key is wd_authkey + * configuration parameter + */ +#define WD_IPC_SHARED_KEY "IPCSharedKey" /* JSON data key for authentication. + * watchdog IPC server use the value of this key + * to authenticate the internal pgpool-II processes + */ + /* Use to inform node new node status by lifecheck */ #define WD_LIFECHECK_NODE_STATUS_DEAD 1 #define WD_LIFECHECK_NODE_STATUS_ALIVE 2 diff --git a/src/include/watchdog/wd_json_data.h b/src/include/watchdog/wd_json_data.h index 53ff9d67d..940f41635 100644 --- a/src/include/watchdog/wd_json_data.h +++ b/src/include/watchdog/wd_json_data.h @@ -43,11 +43,12 @@ extern WatchdogNode* get_watchdog_node_from_json(char* json_data, int data_len, extern char* get_watchdog_node_info_json(WatchdogNode* wdNode, char* authkey); extern POOL_CONFIG* get_pool_config_from_json(char* json_data, int data_len); extern char* get_pool_config_json(void); -extern char* get_lifecheck_node_status_change_json(int nodeID, int nodeStatus, char* message); +extern char* get_lifecheck_node_status_change_json(int nodeID, int nodeStatus, char* message, char* authKey); extern bool parse_node_status_json(char* json_data, int data_len, int* nodeID, int* nodeStatus, char** message); extern WDNodeInfo* get_WDNodeInfo_from_wd_node_json(json_value* source); -extern char* get_wd_node_function_json(char* func_name, int *node_id_set, int count); +extern char* get_wd_node_function_json(char* func_name, int *node_id_set, int count, unsigned int sharedKey, char* authKey); extern bool parse_wd_node_function_json(char* json_data, int data_len, char** func_name, int **node_id_set, int *count); +extern char* get_wd_simple_error_message_json(char* message); #endif diff --git a/src/watchdog/watchdog.c b/src/watchdog/watchdog.c index 6fbb54a9d..89ebb4b0d 100644 --- a/src/watchdog/watchdog.c +++ b/src/watchdog/watchdog.c @@ -261,7 +261,7 @@ typedef struct wd_cluster bool network_error; bool escalated; bool clusterInitialized; - + bool ipc_auth_needed; struct timeval network_error_time; List *unidentified_socks; @@ -364,7 +364,7 @@ static bool wd_commands_packet_processor(WD_EVENTS event, WatchdogNode* wdNode, static WDIPCCommandData* get_wd_IPC_command_from_reply(WDPacketData* pkt); static WDIPCCommandData* get_wd_IPC_command_from_socket(int sock); -static IPC_CMD_PREOCESS_RES process_IPC_command(WDIPCCommandData* IPCCommand); +static IPC_CMD_PREOCESS_RES process_IPC_command(WDIPCCommandData* ipcCommand); static IPC_CMD_PREOCESS_RES process_IPC_nodeStatusChange_command(WDIPCCommandData* IPCCommand); static IPC_CMD_PREOCESS_RES process_IPC_nodeList_command(WDIPCCommandData* IPCCommand); static IPC_CMD_PREOCESS_RES process_IPC_replicate_variable(WDIPCCommandData* IPCCommand); @@ -396,6 +396,8 @@ static void wd_check_config(void); static pid_t watchdog_main(void); static pid_t fork_watchdog_child(void); static void cluster_in_stable_state(void); +static bool check_IPC_client_authentication(json_value *rootObj, bool internal_client_only); +static bool check_and_report_IPC_authentication(WDIPCCommandData* ipcCommand); static void print_received_packet_info(WDPacketData* pkt,WatchdogNode* wdNode); /* global variables */ @@ -506,6 +508,7 @@ static void wd_cluster_initialize(void) g_cluster.ipc_command_socks = NULL; g_cluster.wd_timer_commands = NULL; g_cluster.localNode->state = WD_DEAD; + g_cluster.ipc_auth_needed = strlen(pool_config->wd_authkey)?true:false; /* initialize the memory for command object */ g_cluster.currentCommand.nodeResults = palloc0((sizeof(WDCommandNodeResult) * g_cluster.remoteNodeCount)); @@ -1380,7 +1383,7 @@ static bool read_ipc_command_and_process(int sock, bool *remove_socket) IPCCommand->issueing_sock = sock; IPCCommand->type = type; gettimeofday(&IPCCommand->issue_time, NULL); - + if (data_len > 0) { IPCCommand->data_buf = palloc(data_len); @@ -1425,35 +1428,54 @@ static bool read_ipc_command_and_process(int sock, bool *remove_socket) return (res != IPC_CMD_ERROR); } -static IPC_CMD_PREOCESS_RES process_IPC_command(WDIPCCommandData* IPCCommand) +static IPC_CMD_PREOCESS_RES process_IPC_command(WDIPCCommandData* ipcCommand) { - switch(IPCCommand->type) + /* authenticate the client first */ + if (check_and_report_IPC_authentication(ipcCommand) == false) + { + return IPC_CMD_ERROR; + } + + switch(ipcCommand->type) { case WD_NODE_STATUS_CHANGE_COMMAND: - return process_IPC_nodeStatusChange_command(IPCCommand); + return process_IPC_nodeStatusChange_command(ipcCommand); break; case WD_REGISTER_FOR_NOTIFICATION: /* Add this socket to the notify socket list*/ - g_cluster.notify_clients = lappend_int(g_cluster.notify_clients, IPCCommand->issueing_sock); + g_cluster.notify_clients = lappend_int(g_cluster.notify_clients, ipcCommand->issueing_sock); /* The command is completed successfully */ return IPC_CMD_COMPLETE; break; case WD_GET_NODES_LIST_COMMAND: - return process_IPC_nodeList_command(IPCCommand); + return process_IPC_nodeList_command(ipcCommand); break; case WD_FUNCTION_COMMAND: - return process_IPC_replicate_variable(IPCCommand); + return process_IPC_replicate_variable(ipcCommand); break; case WD_FAILOVER_CMD_SYNC_REQUEST: - return process_IPC_failover_cmd_synchronise(IPCCommand); + return process_IPC_failover_cmd_synchronise(ipcCommand); default: + { + char* error_json; ereport(LOG, - (errmsg("invalid IPC command type %c",IPCCommand->type))); + (errmsg("invalid IPC command type %c",ipcCommand->type))); + + error_json = get_wd_simple_error_message_json("unknown IPC command type"); + if (write_ipc_command_with_result_data(ipcCommand, WD_IPC_CMD_RESULT_BAD, + error_json, strlen(error_json) +1)) + { + ereport(LOG, + (errmsg("failed to forward error message of process node list command to IPC socket"))); + } + pfree(error_json); + + } break; } return IPC_CMD_ERROR; @@ -1479,12 +1501,14 @@ static IPC_CMD_PREOCESS_RES process_IPC_nodeList_command(WDIPCCommandData* IPCCo (errmsg("unable to parse json data from get node list command"))); return IPC_CMD_ERROR; } + /* If it is a node function ?*/ if (json_get_int_value_for_key(root, "NodeID", &NodeID)) { json_value_free(root); return IPC_CMD_ERROR; } + json_value_free(root); jNode = get_node_list_json(NodeID); ret = write_ipc_command_with_result_data(IPCCommand, WD_IPC_CMD_RESULT_OK, @@ -3527,6 +3551,7 @@ static int watchdog_state_machine_joining(WD_EVENTS event, WatchdogNode* wdNode, default: break; } + return 0; } @@ -4951,6 +4976,166 @@ static bool verify_authhash_for_node(WatchdogNode* wdNode, char* authhash) return true; } +/* + * function authenticates the IPC command by looking for the + * auth key in the JSON data of IPC command. + * For IPC commands comming from outer wrold the function validates the + * authkey in JSON packet with configured pool_config->wd_authkey. + * if internal_client_only is true then the JSON data must contain the + * shared key present in the pgpool-II shared memory. This can be used + * to restrict certain watchdog IPC functions for outside of pgpool-II + */ +static bool check_IPC_client_authentication(json_value *rootObj, bool internal_client_only) +{ + char *packet_auth_key; + unsigned int packet_key; + bool has_shared_key; + unsigned int *shared_key = get_ipc_shared_key(); + + if (json_get_int_value_for_key(rootObj, WD_IPC_SHARED_KEY, (int*)&packet_key)) + { + ereport(DEBUG2, + (errmsg("IPC json data packet does not contain shared key"))); + has_shared_key = false; + } + else + { + has_shared_key = true; + } + + if (internal_client_only) + { + + if (shared_key == NULL) + { + ereport(LOG, + (errmsg("shared key not initialized"))); + return false; + } + + /* If it is a node function ?*/ + if (has_shared_key == false) + { + ereport(LOG, + (errmsg("invalid json data packet"), + errdetail("authentication shared key not found in json data"))); + return false; + } + /* compare if shared keys match */ + if (*shared_key != packet_key) + return false; + + /* providing a valid shared key for inetenal clients is enough */ + return true; + } + + /* If no authentication is required, no need to look further */ + if (g_cluster.ipc_auth_needed == false) + return true; + + /* if shared key is provided and it matched, we are good */ + if (has_shared_key == true && *shared_key == packet_key) + return true; + + /* shared key is out of question validate the authKey valurs */ + packet_auth_key = json_get_string_value_for_key(rootObj, WD_IPC_AUTH_KEY); + + if (packet_auth_key == NULL) + { + ereport(DEBUG1, + (errmsg("invalid json data packet"), + errdetail("authentication key not found in json data"))); + return false; + } + + /* compare the packet key with configured auth key */ + if (strcmp(pool_config->wd_authkey, packet_auth_key) != 0) + return false; + return true; +} + +/* + * function to check authentication of IPC command based on the command type + * this one also informs the calling client about the failure + */ + +static bool check_and_report_IPC_authentication(WDIPCCommandData* ipcCommand) +{ + json_value *root = NULL; + bool internal_client_only = false; + bool ret; + + if (ipcCommand == NULL) + return false; /* should never happen*/ + + /* first identify the command type */ + switch(ipcCommand->type) + { + case WD_NODE_STATUS_CHANGE_COMMAND: + case WD_REGISTER_FOR_NOTIFICATION: + case WD_GET_NODES_LIST_COMMAND: + internal_client_only = false; + break; + + case WD_FUNCTION_COMMAND: + case WD_FAILOVER_CMD_SYNC_REQUEST: + /* only allowed internaly.*/ + internal_client_only = true; + break; + + default: + /* unknown command, ignore it */ + return true; + break; + } + + if (internal_client_only == false && g_cluster.ipc_auth_needed == false) + { + /* no need to look further */ + return true; + } + + if (ipcCommand->data_len <= 0 || ipcCommand->data_buf == NULL) + { + ereport(LOG, + (errmsg("authentication failed"), + errdetail("IPC command contains no data"))); + return false; + } + + root = json_parse(ipcCommand->data_buf,ipcCommand->data_len); + /* The root node must be object */ + if (root == NULL || root->type != json_object) + { + json_value_free(root); + ereport(LOG, + (errmsg("authentication failed"), + errdetail("IPC command contains an invalid data"))); + return false; + } + + ret = check_IPC_client_authentication(root, internal_client_only); + json_value_free(root); + + if (ret == false) + { + char* error_json; + ereport(WARNING, + (errmsg("authentication failed"), + errdetail("invalid IPC key"))); + + error_json = get_wd_simple_error_message_json("IPC client authentication failed"); + if (write_ipc_command_with_result_data(ipcCommand, WD_IPC_CMD_RESULT_BAD, + error_json, strlen(error_json) +1)) + { + ereport(LOG, + (errmsg("failed to forward error message to IPC socket"))); + } + pfree(error_json); + } + return ret; +} + /* DEBUG */ static void print_watchdog_node_info(WatchdogNode* wdNode) { diff --git a/src/watchdog/wd_commands.c b/src/watchdog/wd_commands.c index 08b613767..e5ecf2ac3 100644 --- a/src/watchdog/wd_commands.c +++ b/src/watchdog/wd_commands.c @@ -70,8 +70,13 @@ static int wd_chk_node_mask (unsigned char req_mask, int *node_id_set, int count static int open_wd_command_sock(bool throw_error); -unsigned char *WD_Node_List = NULL; /* Lives in shared memory */ -char* watchdog_ipc_address = NULL; +/* shared memory variables */ +unsigned char *WD_Node_List = NULL; +char *watchdog_ipc_address = NULL; +unsigned int *ipc_shared_key = NULL; /* key lives in shared memory + * used to identify the ipc internal + * clients + */ void wd_ipc_initialize_data(void) { @@ -86,6 +91,7 @@ void wd_ipc_initialize_data(void) MAX_WATCHDOG_NUM, sizeof(unsigned char) * MAX_NUM_BACKENDS))); } + if (watchdog_ipc_address == NULL) { char wd_ipc_sock_addr[255]; @@ -96,6 +102,15 @@ void wd_ipc_initialize_data(void) watchdog_ipc_address = pool_shared_memory_create(strlen(wd_ipc_sock_addr) +1); strcpy(watchdog_ipc_address, wd_ipc_sock_addr); } + + if (ipc_shared_key == NULL) + { + ipc_shared_key = pool_shared_memory_create(sizeof(unsigned int)); + *ipc_shared_key = 0; + while (*ipc_shared_key == 0) { + pool_random_salt((char*)ipc_shared_key); + } + } } char* get_watchdog_ipc_address(void) @@ -103,6 +118,11 @@ char* get_watchdog_ipc_address(void) return watchdog_ipc_address; } +unsigned int* get_ipc_shared_key(void) +{ + return ipc_shared_key; +} + /* * function issues the command to watchdog process over the watchdog * IPC command socket. @@ -229,8 +249,11 @@ WdCommandResult wd_start_recovery(void) { char type; - char* func = get_wd_node_function_json(WD_FUNCTION_START_RECOVERY, NULL,0); - + unsigned int *shared_key = get_ipc_shared_key(); + + char* func = get_wd_node_function_json(WD_FUNCTION_START_RECOVERY, NULL,0, + shared_key?*shared_key:0,pool_config->wd_authkey); + WDIPCCmdResult *result = issue_command_to_watchdog(WD_FUNCTION_COMMAND, pool_config->recovery_timeout, func, strlen(func), true); @@ -264,7 +287,11 @@ WdCommandResult wd_end_recovery(void) { char type; - char* func = get_wd_node_function_json(WD_FUNCTION_END_RECOVERY, NULL, 0); + unsigned int *shared_key = get_ipc_shared_key(); + + char* func = get_wd_node_function_json(WD_FUNCTION_END_RECOVERY, NULL, 0, + shared_key?*shared_key:0,pool_config->wd_authkey); + WDIPCCmdResult *result = issue_command_to_watchdog(WD_FUNCTION_COMMAND, WD_DEFAULT_IPC_COMMAND_TIMEOUT, @@ -302,13 +329,15 @@ wd_send_failback_request(int node_id) int n = node_id; char type; char* func; - - + unsigned int *shared_key = get_ipc_shared_key(); + /* if failback packet is received already, do nothing */ if (wd_chk_node_mask_for_failback_req(&n,1)) return COMMAND_OK; - func = get_wd_node_function_json(WD_FUNCTION_FAILBACK_REQUEST,&n, 1); + func = get_wd_node_function_json(WD_FUNCTION_FAILBACK_REQUEST,&n, 1, + shared_key?*shared_key:0,pool_config->wd_authkey); + WDIPCCmdResult *result = issue_command_to_watchdog(WD_FUNCTION_COMMAND, WD_DEFAULT_IPC_COMMAND_TIMEOUT, func, strlen(func), true); @@ -342,7 +371,12 @@ static char* get_wd_failover_cmd_type_json(WDFailoverCMDTypes cmdType, char* req { char* json_str; JsonNode* jNode = jw_create_with_object(true); - + unsigned int *shared_key = get_ipc_shared_key(); + + jw_put_int(jNode, WD_IPC_SHARED_KEY, shared_key?*shared_key:0); /* put the shared key*/ + if (pool_config->wd_authkey != NULL && strlen(pool_config->wd_authkey) > 0) + jw_put_string(jNode, WD_IPC_AUTH_KEY, pool_config->wd_authkey); /* put the auth key*/ + jw_put_int(jNode, "FailoverCMDType", cmdType); jw_put_string(jNode, "SyncRequestType", reqType); jw_finish_document(jNode); @@ -410,13 +444,15 @@ wd_degenerate_backend_set(int *node_id_set, int count) { char type; char* func; - - + unsigned int *shared_key = get_ipc_shared_key(); + /* if failback packet is received already, do nothing */ if (wd_chk_node_mask_for_degenerate_req(node_id_set,count)) return COMMAND_OK; - func = get_wd_node_function_json(WD_FUNCTION_DEGENERATE_REQUEST,node_id_set, count); + func = get_wd_node_function_json(WD_FUNCTION_DEGENERATE_REQUEST,node_id_set, count, + shared_key?*shared_key:0,pool_config->wd_authkey); + WDIPCCmdResult *result = issue_command_to_watchdog(WD_FUNCTION_COMMAND , WD_DEFAULT_IPC_COMMAND_TIMEOUT, func, strlen(func), true); @@ -453,12 +489,14 @@ wd_promote_backend(int node_id) char type; char* func; WDIPCCmdResult *result; - + unsigned int *shared_key = get_ipc_shared_key(); + /* if promote packet is received already, do nothing */ if (wd_chk_node_mask_for_promote_req(&n,1)) return COMMAND_OK; - func = get_wd_node_function_json(WD_FUNCTION_PROMOTE_REQUEST,&n, 1); + func = get_wd_node_function_json(WD_FUNCTION_PROMOTE_REQUEST,&n, 1, + shared_key?*shared_key:0,pool_config->wd_authkey); result = issue_command_to_watchdog(WD_FUNCTION_COMMAND , WD_DEFAULT_IPC_COMMAND_TIMEOUT, func, strlen(func), true); @@ -496,8 +534,16 @@ char* wd_get_watchdog_nodes(int nodeID) { WDIPCCmdResult *result; char* json_str; + unsigned int *shared_key = get_ipc_shared_key(); + JsonNode* jNode = jw_create_with_object(true); jw_put_int(jNode, "NodeID", nodeID); + + jw_put_int(jNode, WD_IPC_SHARED_KEY, shared_key?*shared_key:0); /* put the shared key*/ + + if (pool_config->wd_authkey != NULL && strlen(pool_config->wd_authkey) > 0) + jw_put_string(jNode, WD_IPC_AUTH_KEY, pool_config->wd_authkey); /* put the auth key*/ + jw_finish_document(jNode); json_str = jw_get_json_string(jNode); diff --git a/src/watchdog/wd_json_data.c b/src/watchdog/wd_json_data.c index f7e5f3525..7d567f895 100644 --- a/src/watchdog/wd_json_data.c +++ b/src/watchdog/wd_json_data.c @@ -6,7 +6,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2014 PgPool Global Development Group + * Copyright (c) 2003-2015 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -29,6 +29,7 @@ #include "pool_config.h" #include "watchdog/watchdog.h" #include "watchdog/wd_json_data.h" +#include "watchdog/wd_ipc_defines.h" POOL_CONFIG* get_pool_config_from_json(char* json_data, int data_len) { @@ -310,10 +311,14 @@ WatchdogNode* get_watchdog_node_from_json(char* json_data, int data_len, char** } -char* get_lifecheck_node_status_change_json(int nodeID, int nodeStatus, char* message) +char* get_lifecheck_node_status_change_json(int nodeID, int nodeStatus, char* message, char* authKey) { char* json_str; JsonNode* jNode = jw_create_with_object(true); + + if (authKey != NULL && strlen(authKey) > 0) + jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /* put the auth key*/ + /* add the node ID */ jw_put_int(jNode, "NodeID", nodeID); /* add the node status */ @@ -425,12 +430,17 @@ WDNodeInfo* get_WDNodeInfo_from_wd_node_json(json_value* source) } -char* get_wd_node_function_json(char* func_name, int *node_id_set, int count) +char* get_wd_node_function_json(char* func_name, int *node_id_set, int count, unsigned int sharedKey, char* authKey) { char* json_str; int i; JsonNode* jNode = jw_create_with_object(true); + jw_put_int(jNode, WD_IPC_SHARED_KEY, sharedKey); /* put the shared key*/ + + if (authKey != NULL && strlen(authKey) > 0) + jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /* put the auth key*/ + jw_put_string(jNode, "Function", func_name); jw_put_int(jNode, "NodeCount", count); if (count > 0) @@ -528,4 +538,15 @@ bool parse_wd_node_function_json(char* json_data, int data_len, char** func_name return true; } +char* get_wd_simple_error_message_json(char* message) +{ + char* json_str; + JsonNode* jNode = jw_create_with_object(true); + + jw_put_string(jNode, "ERROR", message); + jw_finish_document(jNode); + json_str = pstrdup(jw_get_json_string(jNode)); + jw_destroy(jNode); + return json_str; +} diff --git a/src/watchdog/wd_lifecheck.c b/src/watchdog/wd_lifecheck.c index 8d638a73b..b516c3fda 100644 --- a/src/watchdog/wd_lifecheck.c +++ b/src/watchdog/wd_lifecheck.c @@ -467,7 +467,7 @@ static bool inform_node_status(LifeCheckNode* node, char *message) (errmsg("informing the node status change to watchdog"), errdetail("node id :%d status = \"%s\" message:\"%s\"",node->ID,new_status,message))); - json_data = get_lifecheck_node_status_change_json(node->ID, node_status, message); + json_data = get_lifecheck_node_status_change_json(node->ID, node_status, message, pool_config->wd_authkey); if (json_data == NULL) return false; [parent: ab1bf7ad6ff2]