root/lib/common/cib_secrets.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_magic_value
  2. check_md5_hash
  3. read_local_file
  4. pcmk__substitute_secrets
  5. add_secret_params

   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 
  26 static int is_magic_value(char *p);
  27 static bool check_md5_hash(char *hash, char *value);
  28 static void add_secret_params(gpointer key, gpointer value, gpointer user_data);
  29 static char *read_local_file(char *local_file);
  30 
  31 #define MAX_VALUE_LEN 255
  32 #define MAGIC "lrm://"
  33 
  34 static int
  35 is_magic_value(char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37     return !strcmp(p, MAGIC);
  38 }
  39 
  40 static bool
  41 check_md5_hash(char *hash, char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
  55 static char *
  56 read_local_file(char *local_file)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
  82 /*!
  83  * \internal
  84  * \brief Read secret parameter values from file
  85  *
  86  * Given a table of resource parameters, if any of their values are the
  87  * magic string indicating a CIB secret, replace that string with the
  88  * secret read from the file appropriate to the given resource.
  89  *
  90  * \param[in]     rsc_id  Resource whose parameters are being checked
  91  * \param[in,out] params  Resource parameters to check
  92  *
  93  * \return Standard Pacemaker return code
  94  */
  95 int
  96 pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
     /* [previous][next][first][last][top][bottom][index][help] */
  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);
 173                 rc = pcmk_rc_cib_corrupt;
 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 
 184 static void
 185 add_secret_params(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */