Windows: Refactor and fix config_reg.c
We want to be able to reuse registry handling code here from elsewhere.
This commit is contained in:
		| @@ -38,7 +38,7 @@ | ||||
| #define REGPATH "SOFTWARE\\Heimdal" | ||||
|  | ||||
| /** | ||||
|  * Parse a registry value as a configuration value | ||||
|  * Parse a registry value as a string | ||||
|  * | ||||
|  * The following registry value types are handled: | ||||
|  * | ||||
| @@ -54,102 +54,153 @@ | ||||
|  *   a separator.  No quoting is performed. | ||||
|  * | ||||
|  * Any other value type is rejected. | ||||
|  * | ||||
|  * @param [in]valuename Name of the registry value to be queried | ||||
|  * @param [in]type      Type of the value. REG_NONE if unknown | ||||
|  * @param [in]cbdata    Size of value. 0 if unknown. | ||||
|  * | ||||
|  * @a type and @a cbdata are only considered valid if both are | ||||
|  * specified. | ||||
|  * | ||||
|  * @retval The registry value string, or NULL if there was an error. | ||||
|  * If NULL is returned, an error message has been set using | ||||
|  * krb5_set_error_message(). | ||||
|  */ | ||||
| static krb5_error_code | ||||
| parse_reg_value(krb5_context context, | ||||
|                 HKEY key, const char * valuename, | ||||
|                 DWORD type, DWORD cbdata, krb5_config_section ** parent) | ||||
| char * | ||||
| _krb5_parse_reg_value_as_string(krb5_context context, | ||||
|                                 HKEY key, const char * valuename, | ||||
|                                 DWORD type, DWORD cb_data) | ||||
| { | ||||
|     LONG                rcode; | ||||
|     DWORD               cb; | ||||
|     LONG                rcode = ERROR_MORE_DATA; | ||||
|     DWORD               cb_alloc; | ||||
|     krb5_config_section *value; | ||||
|     krb5_error_code     code = 0; | ||||
|  | ||||
|     BYTE                static_buffer[16384]; | ||||
|     BYTE                *pbuffer; | ||||
|     char                *ret_string = NULL; | ||||
|  | ||||
|     /* Size adjustments */ | ||||
|     /* If we know a type and cb_data from a previous call to | ||||
|      * RegEnumValue(), we use it.  Otherwise we use the | ||||
|      * static_buffer[] and query directly.  We do this to minimize the | ||||
|      * number of queries. */ | ||||
|  | ||||
|     if (type == REG_NONE || cb_data == 0) { | ||||
|  | ||||
|         pbuffer = &static_buffer[0]; | ||||
|         cb_alloc = cb_data = sizeof(static_buffer); | ||||
|         rcode = RegQueryValueExA(key, valuename, NULL, &type, pbuffer, &cb_data); | ||||
|  | ||||
|         if (rcode == ERROR_SUCCESS && | ||||
|  | ||||
|             ((type != REG_SZ && | ||||
|               type != REG_EXPAND_SZ) || cb_data + 1 <= sizeof(static_buffer)) && | ||||
|  | ||||
|             (type != REG_MULTI_SZ || cb_data + 2 <= sizeof(static_buffer))) | ||||
|             goto have_data; | ||||
|  | ||||
|         if (rcode != ERROR_MORE_DATA && rcode != ERROR_SUCCESS) | ||||
|             return NULL; | ||||
|     } | ||||
|  | ||||
|     /* Either we don't have the data or we aren't sure of the size | ||||
|      * (due to potentially missing terminating NULs). */ | ||||
|  | ||||
|     switch (type) { | ||||
|     case REG_DWORD: | ||||
|         if (cbdata != sizeof(DWORD)) { | ||||
|             krb5_set_error_message(context, KRB5_CONFIG_BADFORMAT, | ||||
|                                    "Unexpected size while reading registry value %s", | ||||
|                                    valuename); | ||||
|             return KRB5_CONFIG_BADFORMAT; | ||||
|         if (cb_data != sizeof(DWORD)) { | ||||
|             if (context) | ||||
|                 krb5_set_error_message(context, 0, | ||||
|                                        "Unexpected size while reading registry value %s", | ||||
|                                        valuename); | ||||
|             return NULL; | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|     case REG_SZ: | ||||
|     case REG_EXPAND_SZ: | ||||
|         cbdata += sizeof(char); /* Accout for potential missing NUL | ||||
|                                  * terminator. */ | ||||
|  | ||||
|         if (rcode == ERROR_SUCCESS && cb_data > 0 && pbuffer[cb_data - 1] == '\0') | ||||
|             goto have_data; | ||||
|  | ||||
|         cb_data += sizeof(char); /* Accout for potential missing NUL | ||||
|                                   * terminator. */ | ||||
|         break; | ||||
|  | ||||
|     case REG_MULTI_SZ: | ||||
|         cbdata += sizeof(char) * 2; | ||||
|  | ||||
|         if (rcode == ERROR_SUCCESS && cb_data > 0 && pbuffer[cb_data - 1] == '\0' && | ||||
|             (cb_data == 1 || pbuffer[cb_data - 2] == '\0')) | ||||
|             goto have_data; | ||||
|  | ||||
|         cb_data += sizeof(char) * 2; /* Potential missing double NUL | ||||
|                                       * terminator. */ | ||||
|         break; | ||||
|  | ||||
|     default: | ||||
|         krb5_set_error_message(context, KRB5_CONFIG_BADFORMAT, | ||||
|                                "Unexpected type while reading registry value %s", | ||||
|                                valuename); | ||||
|         return KRB5_CONFIG_BADFORMAT; | ||||
|         if (context) | ||||
|             krb5_set_error_message(context, 0, | ||||
|                                    "Unexpected type while reading registry value %s", | ||||
|                                    valuename); | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (cbdata <= sizeof(static_buffer)) | ||||
|     if (cb_data <= sizeof(static_buffer)) | ||||
|         pbuffer = &static_buffer[0]; | ||||
|     else { | ||||
|         pbuffer = malloc(cbdata); | ||||
|         pbuffer = malloc(cb_data); | ||||
|         if (pbuffer == NULL) | ||||
|             return ENOMEM; | ||||
|             return NULL; | ||||
|     } | ||||
|  | ||||
|     cb = cbdata; | ||||
|     cb_alloc = cb_data; | ||||
|     rcode = RegQueryValueExA(key, valuename, NULL, NULL, pbuffer, &cb_data); | ||||
|  | ||||
|     rcode = RegQueryValueExA(key, valuename, NULL, NULL, pbuffer, &cb); | ||||
|     if (rcode != ERROR_SUCCESS) { | ||||
|         krb5_set_error_message(context, KRB5_CONFIG_BADFORMAT, | ||||
|                                "Unexpected error while reading registry value %s", | ||||
|                                valuename); | ||||
|         code = KRB5_CONFIG_BADFORMAT; | ||||
|  | ||||
|         /* This can potentially be from a race condition. I.e. some | ||||
|          * other process or thread went and modified the registry | ||||
|          * value between the time we queried its size and queried for | ||||
|          * its value.  Ideally we would retry the query in a loop. */ | ||||
|  | ||||
|         if (context) | ||||
|             krb5_set_error_message(context, 0, | ||||
|                                    "Unexpected error while reading registry value %s", | ||||
|                                    valuename); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     if (cb > cbdata) { | ||||
|         krb5_set_error_message(context, KRB5_CONFIG_BADFORMAT, | ||||
|                                "Unexpected error while reading registry value %s", | ||||
|                                valuename); | ||||
|         code = KRB5_CONFIG_BADFORMAT; | ||||
|     if (cb_data > cb_alloc || cb_data == 0) { | ||||
|         if (context) | ||||
|             krb5_set_error_message(context, 0, | ||||
|                                    "Unexpected size while reading registry value %s", | ||||
|                                    valuename); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     value = _krb5_config_get_entry(parent, valuename, krb5_config_string); | ||||
|     if (value == NULL) { | ||||
|         code = ENOMEM; | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     if (value->u.string != NULL) { | ||||
|         free(value->u.string); | ||||
|         value->u.string = NULL; | ||||
|     } | ||||
|  | ||||
| have_data: | ||||
|     switch (type) { | ||||
|     case REG_DWORD: | ||||
|     { | ||||
|         asprintf(&value->u.string, "%d", *((DWORD *) pbuffer)); | ||||
|     } | ||||
|     break; | ||||
|         asprintf(&ret_string, "%d", *((DWORD *) pbuffer)); | ||||
|         break; | ||||
|  | ||||
|     case REG_SZ: | ||||
|     { | ||||
|         char * str = (char *) pbuffer; | ||||
|  | ||||
|         if (str[cb - 1] != '\0') | ||||
|             str[cb] = '\0'; | ||||
|         if (str[cb_data - 1] != '\0') { | ||||
|             if (cb_data < cb_alloc) | ||||
|                 str[cb_data] = '\0'; | ||||
|             else | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         value->u.string = strdup(str); | ||||
|         if (pbuffer != static_buffer) { | ||||
|             ret_string = (char *) pbuffer; | ||||
|             pbuffer = NULL; | ||||
|         } else { | ||||
|             ret_string = strdup(pbuffer); | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
|  | ||||
| @@ -160,15 +211,20 @@ parse_reg_value(krb5_context context, | ||||
|                                  * ExpandEnvironmentStrings() is | ||||
|                                  * limited to 32K. */ | ||||
|  | ||||
|         if (str[cb - 1] != '\0') | ||||
|             str[cb] = '\0'; | ||||
|         if (str[cb_data - 1] != '\0') { | ||||
|             if (cb_data < cb_alloc) | ||||
|                 str[cb_data] = '\0'; | ||||
|             else | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         if (ExpandEnvironmentStrings(str, expsz, sizeof(expsz)/sizeof(expsz[0])) != 0) { | ||||
|             value->u.string = strdup(expsz); | ||||
|         if (ExpandEnvironmentStrings(str, expsz, sizeof(expsz)/sizeof(char)) != 0) { | ||||
|             ret_string = strdup(expsz); | ||||
|         } else { | ||||
|             code = KRB5_CONFIG_BADFORMAT; | ||||
|             krb5_set_error_message(context, KRB5_CONFIG_BADFORMAT, | ||||
|                                    "Overflow while expanding environment strings for registry value %s", valuename); | ||||
|             if (context) | ||||
|                 krb5_set_error_message(context, 0, | ||||
|                                        "Overflow while expanding environment strings " | ||||
|                                        "for registry value %s", valuename); | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
| @@ -178,8 +234,8 @@ parse_reg_value(krb5_context context, | ||||
|         char * str = (char *) pbuffer; | ||||
|         char * iter; | ||||
|  | ||||
|         str[cbdata - 1] = '\0'; | ||||
|         str[cbdata - 2] = '\0'; | ||||
|         str[cb_alloc - 1] = '\0'; | ||||
|         str[cb_alloc - 2] = '\0'; | ||||
|  | ||||
|         for (iter = str; *iter;) { | ||||
|             size_t len = strlen(iter); | ||||
| @@ -191,15 +247,64 @@ parse_reg_value(krb5_context context, | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         value->u.string = strdup(str); | ||||
|         if (pbuffer != static_buffer) { | ||||
|             ret_string = str; | ||||
|             pbuffer = NULL; | ||||
|         } else { | ||||
|             ret_string = strdup(str); | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
|  | ||||
|     default: | ||||
|         if (context) | ||||
|             krb5_set_error_message(context, 0, | ||||
|                                    "Unexpected type while reading registry value %s", | ||||
|                                    valuename); | ||||
|     } | ||||
|  | ||||
| done: | ||||
|     if (pbuffer != static_buffer && pbuffer != NULL) | ||||
|         free(pbuffer); | ||||
|  | ||||
|     return ret_string; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Parse a registry value as a configuration value | ||||
|  * | ||||
|  * @see parse_reg_value_as_string() | ||||
|  */ | ||||
| static krb5_error_code | ||||
| parse_reg_value(krb5_context context, | ||||
|                 HKEY key, const char * valuename, | ||||
|                 DWORD type, DWORD cbdata, krb5_config_section ** parent) | ||||
| { | ||||
|     char                *reg_string = NULL; | ||||
|     krb5_config_section *value; | ||||
|     krb5_error_code     code = 0; | ||||
|  | ||||
|     reg_string = _krb5_parse_reg_value_as_string(context, key, valuename, type, cbdata); | ||||
|  | ||||
|     if (reg_string == NULL) | ||||
|         return KRB5_CONFIG_BADFORMAT; | ||||
|  | ||||
|     value = _krb5_config_get_entry(parent, valuename, krb5_config_string); | ||||
|     if (value == NULL) { | ||||
|         code = ENOMEM; | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     if (value->u.string != NULL) | ||||
|         free(value->u.string); | ||||
|  | ||||
|     value->u.string = reg_string; | ||||
|     reg_string = NULL; | ||||
|  | ||||
| done: | ||||
|     if (reg_string != NULL) | ||||
|         free(reg_string); | ||||
|  | ||||
|     return code; | ||||
| } | ||||
|  | ||||
| @@ -315,8 +420,8 @@ parse_reg_root(krb5_context context, | ||||
|  * @see parse_reg_value() for details about how each type of value is handled. | ||||
|  */ | ||||
| krb5_error_code | ||||
| krb5_load_config_from_registry(krb5_context context, | ||||
|                                krb5_config_section ** res) | ||||
| _krb5_load_config_from_registry(krb5_context context, | ||||
|                                 krb5_config_section ** res) | ||||
| { | ||||
|     HKEY        key = NULL; | ||||
|     LONG        rcode; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Asanka C. Herath
					Asanka C. Herath