Tightening up the watchdog security
authorMuhammad Usama <m.usama@gmail.com>
Fri, 23 Dec 2016 14:58:53 +0000 (19:58 +0500)
committerMuhammad Usama <m.usama@gmail.com>
Fri, 23 Dec 2016 15:01:06 +0000 (20:01 +0500)
Now wd_authkey uses the HMAC SHA-256 hashing.

src/auth/md5.c
src/include/auth/md5.h
src/watchdog/watchdog.c
src/watchdog/wd_heartbeat.c
src/watchdog/wd_utils.c

index 08bc8b618c9c0bbe5e6d93583629ea23ebc7de6c..69942d2d3a8d07e8fbf509d2805b2a5327aed409 100644 (file)
@@ -317,14 +317,14 @@ calculateDigestFromBuffer(uint8 *b, uint32 len, uint8 sum[16])
        return 1;
 }
 
-static void
-bytesToHex(uint8 b[16], char *s)
+void
+bytesToHex(char *b, int len, char *s)
 {
        static const char *hex = "0123456789abcdef";
        int                     q,
                                w;
 
-       for (q = 0, w = 0; q < 16; q++)
+       for (q = 0, w = 0; q < len; q++)
        {
                s[w++] = hex[(b[q] >> 4) & 0x0F];
                s[w++] = hex[b[q] & 0x0F];
@@ -370,7 +370,7 @@ pool_md5_hash(const void *buff, size_t len, char *hexsum)
        if (!calculateDigestFromBuffer((uint8 *) buff, len, sum))
                return 0;                               /* failed */
 
-       bytesToHex(sum, hexsum);
+       bytesToHex((char *)sum, 16, hexsum);
        return 1;                                       /* success */
 }
 
index 2f3bc482e3fd3c2df8543593ec4d63b62b8b4044..209a9d0db89c18705b70348f9faa6716e2f0c8cc 100644 (file)
@@ -22,7 +22,9 @@
 #define MAX_USER_NAME_LEN 128
 #define MD5_PASSWD_LEN 32
 
+#define WD_AUTH_HASH_LEN 64
+
 extern int pool_md5_hash(const void *buff, size_t len, char *hexsum);
 extern int pool_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf);
-
+extern void bytesToHex(char *b, int len, char *s);
 #endif
index 426a9d714957e9e8351de869cc73a6a86353eb07..418ff2cf131ba06d04c3d5229fc33e51a51c1acc 100644 (file)
@@ -645,7 +645,7 @@ static void wd_cluster_initialize(void)
                g_cluster.remoteNodes[i].pgpool_port = pool_config->wd_remote_nodes.wd_remote_node_info[i].pgpool_port;
                strcpy(g_cluster.remoteNodes[i].hostname, pool_config->wd_remote_nodes.wd_remote_node_info[i].hostname);
                g_cluster.remoteNodes[i].delegate_ip[0] = '\0'; /*this will be populated by remote node*/
-               
+
                ereport(LOG,
                                (errmsg("watchdog remote node:%d on %s:%d",i,g_cluster.remoteNodes[i].hostname, g_cluster.remoteNodes[i].wd_port)));
        }
@@ -677,6 +677,15 @@ static void wd_cluster_initialize(void)
                clear_command_node_result(&g_cluster.currentCommand.nodeResults[i]);
        }
        wd_initialize_monitoring_interfaces();
+       if (g_cluster.ipc_auth_needed)
+       {
+#ifndef USE_SSL
+               ereport(LOG,
+                       (errmsg("watchdog is configured to use authentication, but pgpool-II is built without SSL support"),
+                                errdetail("The authentication method used by pgpool-II without the SSL support is known to be weak")));
+#endif
+       }
+
 }
 
 static void clear_command_node_result(WDCommandNodeResult* nodeResult)
@@ -3344,7 +3353,7 @@ static JsonNode* get_node_list_json(int id)
 
 static WDPacketData* get_addnode_message(void)
 {
-       char authhash[(MD5_PASSWD_LEN+1)*2];
+       char authhash[WD_AUTH_HASH_LEN + 1];
        WDPacketData *message = get_empty_packet();
        bool include_hash = get_authhash_for_node(g_cluster.localNode, authhash);
        char *json_data = get_watchdog_node_info_json(g_cluster.localNode, include_hash?authhash:NULL);
@@ -3357,7 +3366,7 @@ static WDPacketData* get_addnode_message(void)
 
 static WDPacketData* get_mynode_info_message(WDPacketData* replyFor)
 {
-       char authhash[(MD5_PASSWD_LEN+1)*2];
+       char authhash[WD_AUTH_HASH_LEN + 1];
        WDPacketData *message = get_empty_packet();
        bool include_hash = get_authhash_for_node(g_cluster.localNode, authhash);
        char *json_data = get_watchdog_node_info_json(g_cluster.localNode, include_hash?authhash:NULL);
@@ -3543,6 +3552,12 @@ static int standard_packet_processor(WatchdogNode* wdNode, WDPacketData* pkt)
                {
                        char *authkey = NULL;
                        WatchdogNode* tempNode = parse_node_info_message(pkt, &authkey);
+                       if (tempNode == NULL)
+                       {
+                               ereport(WARNING,
+                                       (errmsg("node \"%s\" sent an invalid node info message",wdNode->nodeName)));
+                               break;
+                       }
                        wdNode->state = tempNode->state;
                        wdNode->startup_time.tv_sec = tempNode->startup_time.tv_sec;
                        wdNode->wd_priority = tempNode->wd_priority;
@@ -6191,7 +6206,7 @@ static bool verify_authhash_for_node(WatchdogNode* wdNode, char* authhash)
 {
        if (strlen(pool_config->wd_authkey))
        {
-               char calculated_authhash[(MD5_PASSWD_LEN+1)*2];
+               char calculated_authhash[WD_AUTH_HASH_LEN + 1];
 
                char nodeStr[WD_MAX_PACKET_STRING];
                int len = snprintf(nodeStr, WD_MAX_PACKET_STRING, "state=%d tv_sec=%ld wd_port=%d",
index 67729b5295f623ce58421f9c9bbf22e745ec24c6..4f12b94cc81c165d6c79749a5e65b11dceff66ea 100644 (file)
@@ -61,7 +61,7 @@ typedef struct {
        char from[WD_MAX_HOST_NAMELEN];
        int from_pgpool_port;
        struct timeval send_time;
-       char hash[(MD5_PASSWD_LEN+1)*2];
+       char hash[WD_AUTH_HASH_LEN + 1];
 } WdHbPacket;
 
 
@@ -342,7 +342,7 @@ wd_hb_receiver(int fork_wait_time, WdHbIf *hb_if)
        struct timeval tv;
        char from[WD_MAX_HOST_NAMELEN];
        int from_pgpool_port;
-       char buf[(MD5_PASSWD_LEN+1)*2];
+       char buf[WD_AUTH_HASH_LEN + 1];
        char pack_str[WD_MAX_PACKET_STRING];
        int pack_str_len;
        sigjmp_buf      local_sigjmp_buf;
index cfcb9623162f39a64307ea3c026c4f01ec8d69cc..24cefb3dc409ad5d57d2c4eb2294aad48266d4f2 100644 (file)
@@ -114,6 +114,30 @@ has_setuid_bit(char * path)
 }
 
 
+#ifdef USE_SSL
+/* HMAC SHA-256*/
+static void calculate_hmac_sha256(const char *data, int len, char *buf)
+{
+       char* key = pool_config->wd_authkey;
+       char str[WD_AUTH_HASH_LEN/2];
+
+       unsigned int res_len = WD_AUTH_HASH_LEN;
+
+       HMAC_CTX ctx;
+       HMAC_CTX_init(&ctx);
+       HMAC_Init_ex(&ctx, key, strlen(key), EVP_sha256(), NULL);
+       HMAC_Update(&ctx, (unsigned char*)data, len);
+       HMAC_Final(&ctx, (unsigned char*)str, &res_len);
+       HMAC_CTX_cleanup(&ctx);
+       bytesToHex(str,32,buf);
+       buf[WD_AUTH_HASH_LEN] = '\0';
+}
+void
+wd_calc_hash(const char *str, int len, char *buf)
+{
+       calculate_hmac_sha256(str, len, buf);
+}
+#else
 /* calculate hash for authentication using packet contents */
 void
 wd_calc_hash(const char *str, int len, char *buf)
@@ -123,7 +147,7 @@ wd_calc_hash(const char *str, int len, char *buf)
        size_t pass_len;
        size_t username_len;
        size_t authkey_len;
-
+       char tmp_buf[(MD5_PASSWD_LEN+1)*2];
        /* use first half of authkey as username, last half as password */
        authkey_len = strlen(pool_config->wd_authkey);
 
@@ -133,16 +157,18 @@ wd_calc_hash(const char *str, int len, char *buf)
        username_len = authkey_len / 2;
        pass_len = authkey_len - username_len;
        if ( snprintf(username, username_len + 1, "%s", pool_config->wd_authkey) < 0
-         || snprintf(pass, pass_len + 1, "%s", pool_config->wd_authkey + username_len) < 0)
+               || snprintf(pass, pass_len + 1, "%s", pool_config->wd_authkey + username_len) < 0)
                goto wd_calc_hash_error;
 
        /* calculate hash using md5 encrypt */
-       if (! pool_md5_encrypt(pass, username, strlen(username), buf + MD5_PASSWD_LEN + 1))
+       if (! pool_md5_encrypt(pass, username, strlen(username), tmp_buf + MD5_PASSWD_LEN + 1))
                goto wd_calc_hash_error;
        buf[(MD5_PASSWD_LEN+1)*2-1] = '\0';
 
-       if (! pool_md5_encrypt(buf+MD5_PASSWD_LEN+1, str, len, buf))
+       if (! pool_md5_encrypt(tmp_buf+MD5_PASSWD_LEN+1, str, len, tmp_buf))
                goto wd_calc_hash_error;
+
+       memcpy(buf, tmp_buf, MD5_PASSWD_LEN);
        buf[MD5_PASSWD_LEN] = '\0';
 
        return;
@@ -151,6 +177,7 @@ wd_calc_hash_error:
        buf[0] = '\0';
        return;
 }
+#endif
 
 /*
  * string_replace: