1 /*
2 * $Header$
3 *
4 * Handles watchdog connection, and protocol communication with pgpool-II
5 *
6 * pgpool: a language independent connection pool server for PostgreSQL
7 * written by Tatsuo Ishii
8 *
9 * Copyright (c) 2003-2015 PgPool Global Development Group
10 *
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby
13 * granted, provided that the above copyright notice appear in all
14 * copies and that both that copyright notice and this permission
15 * notice appear in supporting documentation, and that the name of the
16 * author not be used in advertising or publicity pertaining to
17 * distribution of the software without specific, written prior
18 * permission. The author makes no representations about the
19 * suitability of this software for any purpose. It is provided "as
20 * is" without express or implied warranty.
21 *
22 */
23 #include <pthread.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <sys/un.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <sys/wait.h>
33 #include <errno.h>
34
35 #include "pool.h"
36 #include "auth/md5.h"
37 #include "utils/elog.h"
38 #include "utils/palloc.h"
39 #include "utils/memutils.h"
40 #include "pool_config.h"
41 #include "watchdog/wd_utils.h"
42
43 static int has_setuid_bit(char * path);
44 static void *exec_func(void *arg);
45
46 /*
47 * thread information for pool_thread
48 */
49 typedef struct {
50 void *(*start_routine)(void *);
51 void *arg;
52 } WdThreadInfo;
53
54
wd_check_network_command_configurations(void)55 void wd_check_network_command_configurations(void)
56 {
57 char path[128];
58 char* command;
59
60 if (pool_config->use_watchdog == 0)
61 return;
62 /*
63 * If delegate IP is not assigned to the node
64 * the configuration is not used
65 */
66 if (strlen(pool_config->delegate_IP) == 0)
67 return;
68
69 /* check setuid bit of ifup command */
70 command = wd_get_cmd(pool_config->if_up_cmd);
71 if (command)
72 {
73 snprintf(path, sizeof(path), "%s/%s", pool_config->if_cmd_path, command);
74 pfree(command);
75 if (! has_setuid_bit(path))
76 {
77 ereport(WARNING,
78 (errmsg("checking setuid bit of if_up_cmd"),
79 errdetail("ifup[%s] doesn't have setuid bit", path)));
80 }
81 }
82 else
83 {
84 ereport(FATAL,
85 (errmsg("invalid configuration for if_up_cmd parameter"),
86 errdetail("unable to get command from \"%s\"",pool_config->if_up_cmd)));
87 }
88 /* check setuid bit of ifdown command */
89
90 command = wd_get_cmd(pool_config->if_down_cmd);
91 if (command)
92 {
93 snprintf(path, sizeof(path), "%s/%s", pool_config->if_cmd_path, command);
94 pfree(command);
95 if (! has_setuid_bit(path))
96 {
97 ereport(WARNING,
98 (errmsg("checking setuid bit of if_down_cmd"),
99 errdetail("ifdown[%s] doesn't have setuid bit", path)));
100 }
101 }
102 else
103 {
104 ereport(FATAL,
105 (errmsg("invalid configuration for if_down_cmd parameter"),
106 errdetail("unable to get command from \"%s\"",pool_config->if_down_cmd)));
107 }
108
109 /* check setuid bit of arping command */
110 command = wd_get_cmd(pool_config->arping_cmd);
111 if (command)
112 {
113 snprintf(path, sizeof(path), "%s/%s", pool_config->arping_path, command);
114 pfree(command);
115 if (! has_setuid_bit(path))
116 {
117 ereport(WARNING,
118 (errmsg("checking setuid bit of arping command"),
119 errdetail("arping[%s] doesn't have setuid bit", path)));
120 }
121 }
122 else
123 {
124 ereport(FATAL,
125 (errmsg("invalid configuration for arping_cmd parameter"),
126 errdetail("unable to get command from \"%s\"",pool_config->arping_cmd)));
127 }
128
129 }
130
131 /*
132 * if the file has setuid bit and the owner is root, it returns 1, otherwise returns 0
133 */
134 static int
has_setuid_bit(char * path)135 has_setuid_bit(char * path)
136 {
137 struct stat buf;
138 if (stat(path,&buf) < 0)
139 {
140 ereport(FATAL,
141 (return_code(1),
142 errmsg("has_setuid_bit: command '%s' not found", path)));
143 }
144 return ((buf.st_uid == 0) && (S_ISREG(buf.st_mode)) && (buf.st_mode & S_ISUID))?1:0;
145 }
146
147
148 #ifdef USE_SSL
149 /* HMAC SHA-256*/
calculate_hmac_sha256(const char * data,int len,char * buf)150 static void calculate_hmac_sha256(const char *data, int len, char *buf)
151 {
152 char* key = pool_config->wd_authkey;
153 char str[WD_AUTH_HASH_LEN/2];
154 unsigned int res_len = WD_AUTH_HASH_LEN;
155 HMAC_CTX *ctx = NULL;
156
157 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
158 ctx = HMAC_CTX_new();
159 HMAC_CTX_reset(ctx);
160 #else
161 HMAC_CTX ctx_obj;
162 ctx = &ctx_obj;
163 HMAC_CTX_init(ctx);
164 #endif
165 HMAC_Init_ex(ctx, key, strlen(key), EVP_sha256(), NULL);
166 HMAC_Update(ctx, (unsigned char*)data, len);
167 HMAC_Final(ctx, (unsigned char*)str, &res_len);
168 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
169 HMAC_CTX_reset(ctx);
170 HMAC_CTX_free(ctx);
171 #else
172 HMAC_CTX_cleanup(ctx);
173 #endif
174 bytesToHex(str,32,buf);
175 buf[WD_AUTH_HASH_LEN] = '\0';
176 }
177
178 void
wd_calc_hash(const char * str,int len,char * buf)179 wd_calc_hash(const char *str, int len, char *buf)
180 {
181 calculate_hmac_sha256(str, len, buf);
182 }
183 #else
184 /* calculate hash for authentication using packet contents */
185 void
wd_calc_hash(const char * str,int len,char * buf)186 wd_calc_hash(const char *str, int len, char *buf)
187 {
188 char pass[(MAX_PASSWORD_SIZE + 1) / 2];
189 char username[(MAX_PASSWORD_SIZE + 1) / 2];
190 size_t pass_len;
191 size_t username_len;
192 size_t authkey_len;
193 char tmp_buf[(MD5_PASSWD_LEN+1)*2];
194 /* use first half of authkey as username, last half as password */
195 authkey_len = strlen(pool_config->wd_authkey);
196
197 if (len <= 0 || authkey_len <= 0)
198 goto wd_calc_hash_error;
199
200 username_len = authkey_len / 2;
201 pass_len = authkey_len - username_len;
202 if ( snprintf(username, username_len + 1, "%s", pool_config->wd_authkey) < 0
203 || snprintf(pass, pass_len + 1, "%s", pool_config->wd_authkey + username_len) < 0)
204 goto wd_calc_hash_error;
205
206 /* calculate hash using md5 encrypt */
207 if (! pool_md5_encrypt(pass, username, strlen(username), tmp_buf + MD5_PASSWD_LEN + 1))
208 goto wd_calc_hash_error;
209
210 tmp_buf[sizeof(tmp_buf)-1] = '\0';
211
212 if (! pool_md5_encrypt(tmp_buf+MD5_PASSWD_LEN+1, str, len, tmp_buf))
213 goto wd_calc_hash_error;
214
215 memcpy(buf, tmp_buf, MD5_PASSWD_LEN);
216 buf[MD5_PASSWD_LEN] = '\0';
217
218 return;
219
220 wd_calc_hash_error:
221 buf[0] = '\0';
222 return;
223 }
224 #endif
225
226 /*
227 * string_replace:
228 * returns the new palloced string after replacing all
229 * occurances of pattern in string with replacement string
230 */
231 char *
string_replace(const char * string,const char * pattern,const char * replacement)232 string_replace(const char *string, const char *pattern, const char *replacement)
233 {
234 char *tok = NULL;
235 char *newstr = NULL;
236 char *oldstr = NULL;
237 char *head = NULL;
238 size_t pat_len,rep_len;
239
240 newstr = pstrdup(string);
241 /* bail out if no pattern or replacement is given */
242 if ( pattern == NULL || replacement == NULL )
243 return newstr;
244
245 pat_len = strlen(pattern);
246 rep_len = strlen(replacement);
247
248 head = newstr;
249 while ( (tok = strstr(head,pattern)))
250 {
251 oldstr = newstr;
252 newstr = palloc ( strlen ( oldstr ) - pat_len + rep_len + 1 );
253
254 memcpy(newstr, oldstr, tok - oldstr );
255 memcpy(newstr + (tok - oldstr), replacement, rep_len );
256 memcpy(newstr + (tok - oldstr) + rep_len, tok + pat_len, strlen(oldstr) - pat_len - (tok - oldstr));
257 /* put the string terminator */
258 memset( newstr + strlen (oldstr) - pat_len + rep_len , 0, 1 );
259 /* move back head right after the last replacement */
260 head = newstr + (tok - oldstr) + rep_len;
261 pfree(oldstr);
262 }
263 return newstr;
264 }
265
266 /*
267 * The function is wrapper over pthread_create.
268 */
watchdog_thread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)269 int watchdog_thread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
270 {
271 WdThreadInfo* thread_arg = palloc(sizeof(WdThreadInfo));
272 thread_arg->arg = arg;
273 thread_arg->start_routine = start_routine;
274 return pthread_create(thread, attr, exec_func, thread_arg);
275 }
276
277 static void *
exec_func(void * arg)278 exec_func(void *arg)
279 {
280 WdThreadInfo* thread_arg = (WdThreadInfo*) arg;
281 Assert(thread_arg != NULL);
282 return thread_arg->start_routine(thread_arg->arg);
283 }
284
285