diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d77a0e..d114279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to the Zowe Launcher package will be documented in this file. This repo is part of the app-server Zowe Component, and the change logs here may appear on Zowe.org in that section. +## 3.5.0 +- Bugfix: Escape backslash when used in environment variable ([#168](https://github.com/zowe/launcher/pull/168)) + ## 3.4.0 - Enhancement: Message `ZWEL0021I` includes the version of launcher ([#167](https://github.com/zowe/launcher/pull/167)) diff --git a/src/main.c b/src/main.c index b0e33b1..f74a547 100644 --- a/src/main.c +++ b/src/main.c @@ -441,15 +441,19 @@ static bool arrayListContains(ArrayList *list, char *element) { static char* escape_string(char *input) { int length = strlen(input); int quotes = 0; + int backSlashes = 0; for (int i = 0; i < length; i++) { if (input[i] == '\"') quotes++; + if (input[i] == '\\') backSlashes++; } - char *output = malloc(length + quotes + 2 + 1); // add quote on first and the last position and escape quotes inside + // 2 + 1 = add quote on first and the last position and \0 at the end + // quotes & backSlashes = add '\' to escape '"' and '\' + char *output = malloc(length + quotes + backSlashes + 2 + 1); output[0] = '\"'; int j = 1; for (int i = 0; i < length; i++) { - if (input[i] == '\"') { + if (input[i] == '\"' || input[i] == '\\') { output[j++] = '\\'; } output[j++] = input[i]; @@ -469,7 +473,7 @@ static char* jsonToString(Json *json) { return jsonAsBoolean(json) ? "true" : "false"; case JSON_TYPE_NUMBER: case JSON_TYPE_INT64: - output = malloc(21); // Longest string possible -9223372036854775807 + output = malloc(21); // Longest string possible -9223372036854775808 (20+\0) snprintf(output, 21, "%ld", jsonAsInt64(json)); return output; case JSON_TYPE_DOUBLE: @@ -481,11 +485,20 @@ static char* jsonToString(Json *json) { } } -static bool is_valid_key(char *key) { +// Zowe.environments key must follow Unix variable name syntax: +// * The first char must not be a digit +// * Any characters must be either alphanumeric or an underscore +static bool is_key_valid_unix_name(const char *key) { int length = strlen(key); + if (!length) { + return false; + } + if (isdigit(key[0])) { + return false; + } for (int i = 0; i < length; i++) { if (isalnum(key[i])) continue; - if (strchr("_-", key[i])) continue; + if (key[i] == '_') continue; return false; } return true; @@ -541,8 +554,8 @@ static void set_shared_uss_env(ConfigManager *configmgr) { // Get all environment variables defined in zowe.yaml and put them in the output as they are for (JsonProperty *property = jsonObjectGetFirstProperty(object); property != NULL; property = jsonObjectGetNextProperty(property)) { char *key = jsonPropertyGetKey(property); - if (!is_valid_key(key)) { - WARN("Key in zowe.yaml `zowe.environments.%s` is invalid and it will be ignored\n", key); + if (!is_key_valid_unix_name(key)) { + WARN("Key in configuration `zowe.environments.%s` is invalid and it will be ignored\n", key); continue; } diff --git a/test/README.md b/test/README.md index 4e20bc4..04a4715 100644 --- a/test/README.md +++ b/test/README.md @@ -14,3 +14,12 @@ Copyright Contributors to the Zowe Project. Simple shell script to test basic functionality, such as treating items in environment variable `CONFIG`, `haInstace` and typical start-up messages. Return code is the number detected errors. To see an output, use any parameter, for example `./config-syntax.sh print`. + +## Environments + +Script for testing `zowe.environments`: +* Escaping strings with `\` or `"`. It checks only if the variable is in output. +* Ignoring environment variables, which are not valid unix names. +* Return code is the number detected errors. + +See [config](./files/zowe.environments.yaml) used for testing. diff --git a/test/config-syntax.sh b/test/config-syntax.sh index ce7c679..4b9c5e7 100755 --- a/test/config-syntax.sh +++ b/test/config-syntax.sh @@ -8,7 +8,7 @@ # # Copyright Contributors to the Zowe Project. -# Start with_any_paramter -> prints output (diff style) +# Start with any parameter -> prints output (diff style) # rc of this = number of errors found print= diff --git a/test/environments.sh b/test/environments.sh new file mode 100755 index 0000000..05869ca --- /dev/null +++ b/test/environments.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +# This program and the accompanying materials are +# made available under the terms of the Eclipse Public License v2.0 which accompanies +# this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html +# +# SPDX-License-Identifier: EPL-2.0 +# +# Copyright Contributors to the Zowe Project. + +# Start with any parameter -> prints Launcher's output +# rc of this = number of errors found + +print= +errors=0 + +if [ ! -z "${1}" ]; then + print='1' +fi + +LAUNCHER='../bin/zowe_launcher' +if [ ! -f "${LAUNCHER}" ]; then + echo "Executable \"${LAUNCHER}\" not found." + exit 1 +fi + +ZOWE_YAML="./files/zowe.environments.yaml" + +LAUNCHER_OUTPUT= +LAUNCHER_OUTPUT_TEST_VAR= +LAUNCHER_OUTPUT_KEYS= +export ZLDEBUG='ON' +export CONFIG="FILE(${ZOWE_YAML})" + +LAUNCHER_OUTPUT=$("${LAUNCHER}" "ha1" 2>&1) + +if [ ! -z "${print}" ]; then + printf "%s" "${LAUNCHER_OUTPUT}" +fi + +printf "\n---zowe.environments.TEST_VAR_* expected to be used or ignored ---\n\n" +# awk prints between TEST_VAR_START= and TEST_VAR_END= +LAUNCHER_OUTPUT_TEST_VAR=$(printf "%s" "${LAUNCHER_OUTPUT}" | awk '/TEST_VAR_START=/{flag=1}/TEST_VAR_END=/{print; flag=0}flag') +while read -r line; do + if [ -n "$(echo "${line}" | grep 'TEST_VAR_')" ]; then + key=$(echo "${line}" | cut -d: -f1) + if [ -n "$(echo "${line}" | grep '#')" ]; then + output=$(echo "${LAUNCHER_OUTPUT_TEST_VAR}" | grep "${key}") + if [ -n "${output}" ]; then + printf "OK: %s\n" "${output}" + else + echo "Key '${key}' not found!" + errors=`expr $errors + 1` + fi + + fi + fi +done < "${ZOWE_YAML}" + +printf "\n---zowe.environments.* expected to be ignored ---\n\n" +LAUNCHER_OUTPUT_KEYS=$(printf "%s" "${LAUNCHER_OUTPUT}" | grep -e 'Key in configuration') +while read -r line; do + if [ -n "$(echo "${line}" | grep -e '')" ]; then + key="$(echo "${line}" | awk -F: '{ print $1}')" + key="\`zowe.environments.${key}\`" + matchKey="$(printf "%s" "${LAUNCHER_OUTPUT_KEYS}" | grep -e "${key}")" + if [ -n "${matchKey}" ]; then + printf "OK: Key '%s' found: %s\n" "${key}" "${matchKey}" + else + echo "Key '${key}' not found!" + errors=`expr $errors + 1` + fi + fi +done < "${ZOWE_YAML}" + +exit $errors diff --git a/test/fakeRuntime/schemas/server-common.json b/test/fakeRuntime/schemas/server-common.json new file mode 100644 index 0000000..5b9cbb2 --- /dev/null +++ b/test/fakeRuntime/schemas/server-common.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://zowe.org/schemas/v2/server-common", + "title": "Common types", + "description": "Simplified version for testing", + "$defs": { + "semverVersion": { + "$anchor": "zoweSemverVersion", + "type": "string", + "description": "A semantic version, see https://semver.org/", + "pattern": "^[0-9]*\\.[0-9]*\\.[0-9]*(-*[a-zA-Z][0-9a-zA-Z\\-\\.]*)?(\\+[0-9a-zA-Z\\-\\.]*)?$" + } + } +} diff --git a/test/fakeRuntime/schemas/zowe-yaml-schema.json b/test/fakeRuntime/schemas/zowe-yaml-schema.json new file mode 100644 index 0000000..ea0b068 --- /dev/null +++ b/test/fakeRuntime/schemas/zowe-yaml-schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://zowe.org/schemas/v2/server-base", + "title": "Zowe configuration file", + "description": "Simplified version for testing", + "type": "object", + "additionalProperties": false, + "properties": { + "zowe": { + "type": "object" + } + } +} diff --git a/test/files/zowe.environments.yaml b/test/files/zowe.environments.yaml new file mode 100644 index 0000000..66b96fd --- /dev/null +++ b/test/files/zowe.environments.yaml @@ -0,0 +1,82 @@ +zowe: + environments: + TEST_VAR_START: \S\T\A\R\T # "\\S\\T\\A\\R\\T" + # *** Bool *** + TEST_VAR_BOOL_01: true # true + TEST_VAR_BOOL_02: false # false + TEST_VAR_BOOL_03: !!bool true # true + TEST_VAR_BOOL_04: !!bool false # false + # *** Int *** + TEST_VAR_INT_01: 123456 # 123456 + TEST_VAR_INT_02: !!int 123456 # 123456 + TEST_VAR_INT_03: 0x7FFFFFFF # 2147483647 + TEST_VAR_INT_04: 0x00000001 # 1 + TEST_VAR_INT_05: !!int 0x7FFFFFFF # 2147483647 + TEST_VAR_INT_06: !!int 0x00000001 # 1 + TEST_VAR_INT_07: 9223372036854775807 # 9223372036854775807 + TEST_VAR_INT_08: !!int 9223372036854775807 # 9223372036854775807 + TEST_VAR_INT_09: -9223372036854775808 # -9223372036854775808 + TEST_VAR_INT_10: !!int -9223372036854775808 # -9223372036854775808 + # *** Str *** + TEST_VAR_STR_01: \\\\\\\\\\ # "\\\\\\\\\\\\\\\\\\\\" + TEST_VAR_STR_02: !!str \\\\\\\\\\ # "\\\\\\\\\\\\\\\\\\\\" + TEST_VAR_STR_03: '""""""""""' # "\"\"\"\"\"\"\"\"\"\"" + TEST_VAR_STR_04: '"' # "\"" + TEST_VAR_STR_05: \n # "\\n" + TEST_VAR_STR_06: \0 # "\\0" + TEST_VAR_STR_07: 'TE\"ST' # "TE\\\"ST" + TEST_VAR_STR_08: "TE\"ST" # "TE\"ST" + TEST_VAR_STR_09: TE\"ST # "TE\\\"ST" + TEST_VAR_STR_10: !!str 123 # "123" + TEST_VAR_STR_11: !!str true # "true" + TEST_VAR_STR_12: |- # William Shakespeare: All's Well That Ends Well + Love all, trust a few, + Do wrong to none: be able for thine enemy + Rather in power than use; and keep thy friend + Under thy own life's key: be check'd for silence, + But never tax'd for speech. + # *** Null *** + TEST_VAR_NULL_01: + TEST_VAR_NULL_02: ~ + TEST_VAR_NULL_03: null + # *** Array *** + TEST_VAR_ARRAY_01: + - kiwi + - banana + - orange + TEST_VAR_ARRAY_02: ['A', 'B', 'C'] + TEST_VAR_NESTED: + enabled: true + disabled: false + # *** Embedded JS *** + TEST_VAR_EJS_01: "${{ zowe.environments.TEST_VAR_INT_01 }}" # zowe.environments.TEST_VAR_INT_01 + TEST_VAR_EJS_02: "${{ 1+1*7 }}" # 8 + TEST_VAR_EJS_03: "${{ 'EJS' }}" # "EJS" + TEST_VAR_EJS_04: "${{ `EJS` }}" # "EJS" + TEST_VAR_EJS_05: "${{ \"EJS\" }}" # "EJS" + TEST_VAR_EJS_06: "${{ `E` + 'J' + \"S\" }}" # "EJS" + TEST_VAR_EJS_07: "${{ `\\` }}" # "\\" + TEST_VAR_EJS_08: "${{ /* # true */ + () => { if (1 == 1) return true } (); + }}" + TEST_VAR_END: \E\N\D # "\\E\\N\\D" + # *** Ignored keys *** + -key-: ~ # + ?key: '?' # + 1+1: =2 # + 1-1: "=0" # + _!_: '!!!' # + 1TEST: true # + 3_141592: 6535 # + (): !!int 0 # + ~null: not null # + =: equal sign # +

: heading # + runtimeDirectory: "${{ () => { + let thisPath = os.realpath('./fakeRuntime'); + if (thisPath[1] == 0) { + return thisPath[0]; + } + return undefined; + } () + }}"