pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
cib_secrets.c
Go to the documentation of this file.
1/*
2 * Copyright 2011-2020 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <unistd.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <ctype.h>
17#include <errno.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <time.h>
21
22#include <glib.h>
23
24#include <crm/common/util.h>
25
26static int is_magic_value(char *p);
27static bool check_md5_hash(char *hash, char *value);
28static void add_secret_params(gpointer key, gpointer value, gpointer user_data);
29static char *read_local_file(char *local_file);
30
31#define MAX_VALUE_LEN 255
32#define MAGIC "lrm://"
33
34static int
35is_magic_value(char *p)
36{
37 return !strcmp(p, MAGIC);
38}
39
40static bool
41check_md5_hash(char *hash, char *value)
42{
43 bool rc = false;
44 char *hash2 = NULL;
45
46 hash2 = crm_md5sum(value);
47 crm_debug("hash: %s, calculated hash: %s", hash, hash2);
48 if (pcmk__str_eq(hash, hash2, pcmk__str_casei)) {
49 rc = true;
50 }
51 free(hash2);
52 return rc;
53}
54
55static char *
56read_local_file(char *local_file)
57{
58 FILE *fp = fopen(local_file, "r");
59 char buf[MAX_VALUE_LEN+1];
60 char *p;
61
62 if (!fp) {
63 if (errno != ENOENT) {
64 crm_perror(LOG_ERR, "cannot open %s" , local_file);
65 }
66 return NULL;
67 }
68
69 if (!fgets(buf, MAX_VALUE_LEN, fp)) {
70 crm_perror(LOG_ERR, "cannot read %s", local_file);
71 fclose(fp);
72 return NULL;
73 }
74 fclose(fp);
75
76 // Strip trailing white space
77 for (p = buf + strlen(buf) - 1; (p >= buf) && isspace(*p); p--);
78 *(p+1) = '\0';
79 return strdup(buf);
80}
81
95int
96pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
97{
98 char local_file[FILENAME_MAX+1], *start_pname;
99 char hash_file[FILENAME_MAX+1], *hash;
100 GList *secret_params = NULL, *l;
101 char *key, *pvalue, *secret_value;
102 int rc = pcmk_rc_ok;
103
104 if (params == NULL) {
105 return pcmk_rc_ok;
106 }
107
108 /* secret_params could be cached with the resource;
109 * there are also parameters sent with operations
110 * which cannot be cached
111 */
112 g_hash_table_foreach(params, add_secret_params, &secret_params);
113 if (secret_params == NULL) { // No secret parameters found
114 return pcmk_rc_ok;
115 }
116
117 crm_debug("Replace secret parameters for resource %s", rsc_id);
118
119 if (snprintf(local_file, FILENAME_MAX, LRM_CIBSECRETS_DIR "/%s/", rsc_id)
120 > FILENAME_MAX) {
121 crm_err("Can't replace secret parameters for %s: file name size exceeded",
122 rsc_id);
123 return ENAMETOOLONG;
124 }
125 start_pname = local_file + strlen(local_file);
126
127 for (l = g_list_first(secret_params); l; l = g_list_next(l)) {
128 key = (char *)(l->data);
129 pvalue = g_hash_table_lookup(params, key);
130 if (!pvalue) { /* this cannot really happen */
131 crm_err("odd, no parameter %s for rsc %s found now", key, rsc_id);
132 continue;
133 }
134
135 if ((strlen(key) + strlen(local_file)) >= FILENAME_MAX-2) {
136 crm_err("%s: parameter name %s too big", rsc_id, key);
137 rc = ENAMETOOLONG;
138 continue;
139 }
140
141 strcpy(start_pname, key);
142 secret_value = read_local_file(local_file);
143 if (!secret_value) {
144 crm_err("secret for rsc %s parameter %s not found in %s",
145 rsc_id, key, LRM_CIBSECRETS_DIR);
146 rc = ENOENT;
147 continue;
148 }
149
150 strcpy(hash_file, local_file);
151 if (strlen(hash_file) + 5 > FILENAME_MAX) {
152 crm_err("cannot build such a long name "
153 "for the sign file: %s.sign", hash_file);
154 free(secret_value);
155 rc = ENAMETOOLONG;
156 continue;
157
158 } else {
159 strcat(hash_file, ".sign");
160 hash = read_local_file(hash_file);
161 if (hash == NULL) {
162 crm_err("md5 sum for rsc %s parameter %s "
163 "cannot be read from %s", rsc_id, key, hash_file);
164 free(secret_value);
165 rc = ENOENT;
166 continue;
167
168 } else if (!check_md5_hash(hash, secret_value)) {
169 crm_err("md5 sum for rsc %s parameter %s "
170 "does not match", rsc_id, key);
171 free(secret_value);
172 free(hash);
174 continue;
175 }
176 free(hash);
177 }
178 g_hash_table_replace(params, strdup(key), secret_value);
179 }
180 g_list_free(secret_params);
181 return rc;
182}
183
184static void
185add_secret_params(gpointer key, gpointer value, gpointer user_data)
186{
187 GList **lp = (GList **)user_data;
188
189 if (is_magic_value((char *)value)) {
190 *lp = g_list_append(*lp, (char *)key);
191 }
192}
#define MAX_VALUE_LEN
Definition: cib_secrets.c:31
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:96
#define MAGIC
Definition: cib_secrets.c:32
Utility functions.
char * crm_md5sum(const char *buffer)
Definition: digest.c:256
#define LRM_CIBSECRETS_DIR
Definition: config.h:453
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:310
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_err(fmt, args...)
Definition: logging.h:359
@ pcmk_rc_ok
Definition: results.h:148
@ pcmk_rc_cib_corrupt
Definition: results.h:137
@ pcmk__str_casei