From: Petr Hodina <[email protected]>

Extend cmdline_utils to support masking or replacing parameters in
command line strings. This is useful for filtering sensitive data or
modifying boot parameters.

Signed-off-by: Petr Hodina <[email protected]>
---
 include/cmdline_utils.h |   7 +++
 lib/cmdline_utils.c     | 150 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 157 insertions(+)

diff --git a/include/cmdline_utils.h b/include/cmdline_utils.h
index cf127b64e55..fa6e20b2417 100644
--- a/include/cmdline_utils.h
+++ b/include/cmdline_utils.h
@@ -18,4 +18,11 @@ struct cmdline_param {
 
 int parse_cmdline_params(const char *cmdline, struct cmdline_param *params, 
int count);
 
+struct cmdline_mask_param {
+       const char *key;
+       const char *new_value;
+};
+
+char *mask_cmdline_params(const char *cmdline, struct cmdline_mask_param 
*params, int count);
+
 #endif /* _CMDLINE_UTILS_H_ */
diff --git a/lib/cmdline_utils.c b/lib/cmdline_utils.c
index b4798c439b8..4355bdd45f4 100644
--- a/lib/cmdline_utils.c
+++ b/lib/cmdline_utils.c
@@ -94,3 +94,153 @@ cleanup_error:
        }
        return -ENOMEM;
 }
+
+static int ensure_capacity(char **result, int *result_len, char **dst_pos, int 
needed)
+{
+       int current_pos = *dst_pos - *result;
+       char *temp;
+
+       if (current_pos + needed < *result_len)
+               return 0;
+
+       while (current_pos + needed >= *result_len)
+               *result_len *= 2;
+
+       temp = realloc(*result, *result_len + 1);
+       if (!temp) {
+               free(*result);
+               return -ENOMEM;
+       }
+
+       *result = temp;
+       *dst_pos = *result + current_pos;
+
+       return 0;
+}
+
+static int write_replacement(char **result, int *result_len, char **dst_pos,
+                            const char *key_with_equals, const char *new_value)
+{
+       int key_len = strlen(key_with_equals);
+       int new_value_len = strlen(new_value);
+
+       if (ensure_capacity(result, result_len, dst_pos, key_len + 
new_value_len))
+               return -ENOMEM;
+
+       memcpy(*dst_pos, key_with_equals, key_len);
+       *dst_pos += key_len;
+
+       strcpy(*dst_pos, new_value);
+       *dst_pos += new_value_len;
+
+       return 0;
+}
+
+enum match_result {
+       NO_MATCH,
+       MATCHED,
+       MATCH_ERROR,
+};
+
+static enum match_result apply_mask_param(const char *cmdline, const char 
*src_pos,
+                                         struct cmdline_mask_param *param,
+                                         char **result, int *result_len, char 
**dst_pos,
+                                         const char **next_src_pos)
+{
+       char *key_with_equals;
+       int key_len;
+       const char *value_start, *value_end, *param_end;
+       enum match_result ret;
+
+       if (!param->key)
+               return NO_MATCH;
+
+       key_len = strlen(param->key);
+       if (param->key[key_len - 1] == '=') {
+               key_with_equals = (char *)param->key;
+       } else {
+               key_with_equals = malloc(key_len + 2);
+               if (!key_with_equals) {
+                       free(*result);
+                       return MATCH_ERROR;
+               }
+               strcpy(key_with_equals, param->key);
+               strcat(key_with_equals, "=");
+       }
+
+       if (strncmp(src_pos, key_with_equals, strlen(key_with_equals)) != 0 ||
+           (src_pos != cmdline && *(src_pos - 1) != ' ')) {
+               ret = NO_MATCH;
+               goto out;
+       }
+
+       value_start = src_pos + strlen(key_with_equals);
+       value_end = strstr(value_start, " ");
+       if (!value_end)
+               value_end = value_start + strlen(value_start);
+       param_end = value_end;
+
+       if (!param->new_value) {
+               *next_src_pos = (*param_end == ' ') ? param_end + 1 : param_end;
+       } else if (write_replacement(result, result_len, dst_pos,
+                                     key_with_equals, param->new_value)) {
+               ret = MATCH_ERROR;
+               goto out;
+       } else {
+               *next_src_pos = param_end;
+       }
+
+       ret = MATCHED;
+
+out:
+       if (key_with_equals != param->key)
+               free(key_with_equals);
+       return ret;
+}
+
+char *mask_cmdline_params(const char *cmdline, struct cmdline_mask_param 
*params, int count)
+{
+       char *result;
+       const char *src_pos;
+       char *dst_pos;
+       int i, result_len, cmdline_len;
+       bool found_match;
+
+       if (!cmdline || !params || count <= 0)
+               return NULL;
+
+       cmdline_len = strlen(cmdline);
+       result_len = cmdline_len * 2;
+       result = malloc(result_len + 1);
+       if (!result)
+               return NULL;
+
+       src_pos = cmdline;
+       dst_pos = result;
+
+       while (*src_pos) {
+               found_match = false;
+
+               for (i = 0; i < count; i++) {
+                       enum match_result mr;
+
+                       mr = apply_mask_param(cmdline, src_pos, &params[i],
+                                             &result, &result_len, &dst_pos, 
&src_pos);
+                       if (mr == MATCH_ERROR)
+                               return NULL;
+                       if (mr == MATCHED) {
+                               found_match = true;
+                               break;
+                       }
+               }
+
+               if (!found_match) {
+                       if (ensure_capacity(&result, &result_len, &dst_pos, 1))
+                               return NULL;
+                       *dst_pos++ = *src_pos++;
+               }
+       }
+
+       *dst_pos = '\0';
+       return result;
+}

-- 
2.55.0


Reply via email to