659 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			659 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/***********************************************************************
 | 
						|
 * Copyright (c) 2010, Secure Endpoints Inc.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 *
 | 
						|
 * - Redistributions of source code must retain the above copyright
 | 
						|
 *   notice, this list of conditions and the following disclaimer.
 | 
						|
 *
 | 
						|
 * - Redistributions in binary form must reproduce the above copyright
 | 
						|
 *   notice, this list of conditions and the following disclaimer in
 | 
						|
 *   the documentation and/or other materials provided with the
 | 
						|
 *   distribution.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
						|
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
						|
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 | 
						|
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
						|
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
						|
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 | 
						|
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
						|
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 | 
						|
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 *
 | 
						|
 **********************************************************************/
 | 
						|
 | 
						|
#include "baselocl.h"
 | 
						|
 | 
						|
#ifndef _WIN32
 | 
						|
#error  config_reg.c is only for Windows
 | 
						|
#endif
 | 
						|
 | 
						|
#include <shlwapi.h>
 | 
						|
 | 
						|
#ifndef MAX_DWORD
 | 
						|
#define MAX_DWORD 0xFFFFFFFF
 | 
						|
#endif
 | 
						|
 | 
						|
/**
 | 
						|
 * Store a string as a registry value of the specified type
 | 
						|
 *
 | 
						|
 * The following registry types are handled:
 | 
						|
 *
 | 
						|
 * - REG_DWORD: The string is converted to a number.
 | 
						|
 *
 | 
						|
 * - REG_SZ: The string is stored as is.
 | 
						|
 *
 | 
						|
 * - REG_EXPAND_SZ: The string is stored as is.
 | 
						|
 *
 | 
						|
 * - REG_MULTI_SZ:
 | 
						|
 *
 | 
						|
 *   . If a separator is specified, the input string is broken
 | 
						|
 *     up into multiple strings and stored as a multi-sz.
 | 
						|
 *
 | 
						|
 *   . If no separator is provided, the input string is stored
 | 
						|
 *     as a multi-sz.
 | 
						|
 *
 | 
						|
 * - REG_NONE:
 | 
						|
 *
 | 
						|
 *   . If the string is all numeric, it will be stored as a
 | 
						|
 *     REG_DWORD.
 | 
						|
 *
 | 
						|
 *   . Otherwise, the string is stored as a REG_SZ.
 | 
						|
 *
 | 
						|
 * Other types are rejected.
 | 
						|
 *
 | 
						|
 * If cb_data is MAX_DWORD, the string pointed to by data must be nul-terminated
 | 
						|
 * otherwise a buffer overrun will occur.
 | 
						|
 *
 | 
						|
 * @param [in]valuename Name of the registry value to be modified or created
 | 
						|
 * @param [in]type      Type of the value. REG_NONE if unknown
 | 
						|
 * @param [in]data      The input string to be stored in the registry.
 | 
						|
 * @param [in]cb_data   Size of the input string in bytes. MAX_DWORD if unknown.
 | 
						|
 * @param [in]separator Separator character for parsing strings.
 | 
						|
 *
 | 
						|
 * @retval 0 if success or non-zero on error.
 | 
						|
 * If non-zero is returned, an error message has been set using
 | 
						|
 * heim_set_error_message().
 | 
						|
 *
 | 
						|
 */
 | 
						|
int
 | 
						|
heim_store_string_to_reg_value(heim_context context,
 | 
						|
                               HKEY key, const char *valuename,
 | 
						|
                               DWORD type, const char *data, DWORD cb_data,
 | 
						|
                               const char *separator)
 | 
						|
{
 | 
						|
    LONG        rcode;
 | 
						|
    int         dwData;
 | 
						|
    BYTE        static_buffer[16384];
 | 
						|
 | 
						|
    if (data == NULL)
 | 
						|
    {
 | 
						|
        if (context)
 | 
						|
            heim_set_error_message(context, 0,
 | 
						|
                                   "'data' must not be NULL");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cb_data == MAX_DWORD)
 | 
						|
    {
 | 
						|
        cb_data = (DWORD)strlen(data) + 1;
 | 
						|
    }
 | 
						|
    else if ((type == REG_MULTI_SZ && cb_data >= sizeof(static_buffer) - 1) ||
 | 
						|
             cb_data >= sizeof(static_buffer))
 | 
						|
    {
 | 
						|
        if (context)
 | 
						|
            heim_set_error_message(context, 0, "cb_data too big");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    else if (data[cb_data-1] != '\0')
 | 
						|
    {
 | 
						|
        memcpy(static_buffer, data, cb_data);
 | 
						|
        static_buffer[cb_data++] = '\0';
 | 
						|
        if (type == REG_MULTI_SZ)
 | 
						|
            static_buffer[cb_data++] = '\0';
 | 
						|
        data = static_buffer;
 | 
						|
    }
 | 
						|
 | 
						|
    if (type == REG_NONE)
 | 
						|
    {
 | 
						|
        /*
 | 
						|
         * If input is all numeric, convert to DWORD and save as REG_DWORD.
 | 
						|
         * Otherwise, store as REG_SZ.
 | 
						|
         */
 | 
						|
        if ( StrToIntExA( data, STIF_SUPPORT_HEX, &dwData) )
 | 
						|
        {
 | 
						|
            type = REG_DWORD;
 | 
						|
        } else {
 | 
						|
            type = REG_SZ;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    switch (type) {
 | 
						|
    case REG_SZ:
 | 
						|
    case REG_EXPAND_SZ:
 | 
						|
        rcode = RegSetValueEx(key, valuename, 0, type, data, cb_data);
 | 
						|
        if (rcode)
 | 
						|
        {
 | 
						|
            if (context)
 | 
						|
                heim_set_error_message(context, 0,
 | 
						|
                                       "Unexpected error when setting registry value %s gle 0x%x",
 | 
						|
                                       valuename,
 | 
						|
                                       GetLastError());
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    case REG_MULTI_SZ:
 | 
						|
        if (separator && *separator)
 | 
						|
        {
 | 
						|
            char *cp;
 | 
						|
 | 
						|
            if (data != static_buffer)
 | 
						|
                static_buffer[cb_data++] = '\0';
 | 
						|
 | 
						|
            for ( cp = static_buffer; cp < static_buffer+cb_data; cp++)
 | 
						|
            {
 | 
						|
                if (*cp == *separator)
 | 
						|
                    *cp = '\0';
 | 
						|
            }
 | 
						|
 | 
						|
            rcode = RegSetValueEx(key, valuename, 0, type, data, cb_data);
 | 
						|
            if (rcode)
 | 
						|
            {
 | 
						|
                if (context)
 | 
						|
                    heim_set_error_message(context, 0,
 | 
						|
                                           "Unexpected error when setting registry value %s gle 0x%x",
 | 
						|
                                           valuename,
 | 
						|
                                           GetLastError());
 | 
						|
                return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    case REG_DWORD:
 | 
						|
        if ( !StrToIntExA( data, STIF_SUPPORT_HEX, &dwData) )
 | 
						|
        {
 | 
						|
            if (context)
 | 
						|
                heim_set_error_message(context, 0,
 | 
						|
                                       "Unexpected error when parsing %s as number gle 0x%x",
 | 
						|
                                       data,
 | 
						|
                                       GetLastError());
 | 
						|
        }
 | 
						|
 | 
						|
	rcode = RegSetValueEx(key, valuename, 0, type, (BYTE *)&dwData, sizeof(DWORD));
 | 
						|
        if (rcode)
 | 
						|
        {
 | 
						|
            if (context)
 | 
						|
                heim_set_error_message(context, 0,
 | 
						|
                                       "Unexpected error when setting registry value %s gle 0x%x",
 | 
						|
                                       valuename,
 | 
						|
                                       GetLastError());
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Parse a registry value as a string
 | 
						|
 *
 | 
						|
 * @see heim_parse_reg_value_as_multi_string()
 | 
						|
 */
 | 
						|
char *
 | 
						|
heim_parse_reg_value_as_string(heim_context context,
 | 
						|
                               HKEY key, const char * valuename,
 | 
						|
                               DWORD type, DWORD cb_data)
 | 
						|
{
 | 
						|
    return heim_parse_reg_value_as_multi_string(context, key, valuename,
 | 
						|
                                                type, cb_data, " ");
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Parse a registry value as a multi string
 | 
						|
 *
 | 
						|
 * The following registry value types are handled:
 | 
						|
 *
 | 
						|
 * - REG_DWORD: The decimal string representation is used as the
 | 
						|
 *   value.
 | 
						|
 *
 | 
						|
 * - REG_SZ: The string is used as-is.
 | 
						|
 *
 | 
						|
 * - REG_EXPAND_SZ: Environment variables in the string are expanded
 | 
						|
 *   and the result is used as the value.
 | 
						|
 *
 | 
						|
 * - REG_MULTI_SZ: The list of strings is concatenated using the
 | 
						|
 *   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.
 | 
						|
 * @param [in]separator Separator character for concatenating strings.
 | 
						|
 *
 | 
						|
 * @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
 | 
						|
 * heim_set_error_message().
 | 
						|
 */
 | 
						|
char *
 | 
						|
heim_parse_reg_value_as_multi_string(heim_context context,
 | 
						|
                                     HKEY key, const char * valuename,
 | 
						|
                                     DWORD type, DWORD cb_data, char *separator)
 | 
						|
{
 | 
						|
    LONG                rcode = ERROR_MORE_DATA;
 | 
						|
 | 
						|
    BYTE                static_buffer[16384];
 | 
						|
    BYTE                *pbuffer = &static_buffer[0];
 | 
						|
    DWORD               cb_alloc = sizeof(static_buffer);
 | 
						|
    char                *ret_string = NULL;
 | 
						|
 | 
						|
    /* 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 (cb_data != sizeof(DWORD)) {
 | 
						|
            if (context)
 | 
						|
                heim_set_error_message(context, 0,
 | 
						|
                                       "Unexpected size while reading registry value %s",
 | 
						|
                                       valuename);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
    case REG_SZ:
 | 
						|
    case REG_EXPAND_SZ:
 | 
						|
 | 
						|
        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:
 | 
						|
 | 
						|
        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:
 | 
						|
        if (context)
 | 
						|
            heim_set_error_message(context, 0,
 | 
						|
                                   "Unexpected type while reading registry value %s",
 | 
						|
                                   valuename);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cb_data <= sizeof(static_buffer))
 | 
						|
        pbuffer = &static_buffer[0];
 | 
						|
    else {
 | 
						|
        pbuffer = malloc(cb_data);
 | 
						|
        if (pbuffer == NULL)
 | 
						|
            return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    cb_alloc = cb_data;
 | 
						|
    rcode = RegQueryValueExA(key, valuename, NULL, NULL, pbuffer, &cb_data);
 | 
						|
 | 
						|
    if (rcode != ERROR_SUCCESS) {
 | 
						|
 | 
						|
        /* 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)
 | 
						|
            heim_set_error_message(context, 0,
 | 
						|
                                   "Unexpected error while reading registry value %s",
 | 
						|
                                   valuename);
 | 
						|
        goto done;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cb_data > cb_alloc || cb_data == 0) {
 | 
						|
        if (context)
 | 
						|
            heim_set_error_message(context, 0,
 | 
						|
                                   "Unexpected size while reading registry value %s",
 | 
						|
                                   valuename);
 | 
						|
        goto done;
 | 
						|
    }
 | 
						|
 | 
						|
have_data:
 | 
						|
    switch (type) {
 | 
						|
    case REG_DWORD:
 | 
						|
        asprintf(&ret_string, "%d", *((DWORD *) pbuffer));
 | 
						|
        break;
 | 
						|
 | 
						|
    case REG_SZ:
 | 
						|
    {
 | 
						|
        char * str = (char *) pbuffer;
 | 
						|
 | 
						|
        if (str[cb_data - 1] != '\0') {
 | 
						|
            if (cb_data < cb_alloc)
 | 
						|
                str[cb_data] = '\0';
 | 
						|
            else
 | 
						|
                break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (pbuffer != static_buffer) {
 | 
						|
            ret_string = (char *) pbuffer;
 | 
						|
            pbuffer = NULL;
 | 
						|
        } else {
 | 
						|
            ret_string = strdup((char *) pbuffer);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
    case REG_EXPAND_SZ:
 | 
						|
    {
 | 
						|
        char    *str = (char *) pbuffer;
 | 
						|
        char    expsz[32768];   /* Size of output buffer for
 | 
						|
                                 * ExpandEnvironmentStrings() is
 | 
						|
                                 * limited to 32K. */
 | 
						|
 | 
						|
        if (str[cb_data - 1] != '\0') {
 | 
						|
            if (cb_data < cb_alloc)
 | 
						|
                str[cb_data] = '\0';
 | 
						|
            else
 | 
						|
                break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (ExpandEnvironmentStrings(str, expsz, sizeof(expsz)/sizeof(char)) != 0) {
 | 
						|
            ret_string = strdup(expsz);
 | 
						|
        } else {
 | 
						|
            if (context)
 | 
						|
                heim_set_error_message(context, 0,
 | 
						|
                                       "Overflow while expanding environment strings "
 | 
						|
                                       "for registry value %s", valuename);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
    case REG_MULTI_SZ:
 | 
						|
    {
 | 
						|
        char * str = (char *) pbuffer;
 | 
						|
        char * iter;
 | 
						|
 | 
						|
        str[cb_alloc - 1] = '\0';
 | 
						|
        str[cb_alloc - 2] = '\0';
 | 
						|
 | 
						|
        for (iter = str; *iter;) {
 | 
						|
            size_t len = strlen(iter);
 | 
						|
 | 
						|
            iter += len;
 | 
						|
            if (iter[1] != '\0')
 | 
						|
                *iter++ = *separator;
 | 
						|
            else
 | 
						|
                break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (pbuffer != static_buffer) {
 | 
						|
            ret_string = str;
 | 
						|
            pbuffer = NULL;
 | 
						|
        } else {
 | 
						|
            ret_string = strdup(str);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
    default:
 | 
						|
        if (context)
 | 
						|
            heim_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 heim_error_code
 | 
						|
parse_reg_value(heim_context context,
 | 
						|
                HKEY key, const char * valuename,
 | 
						|
                DWORD type, DWORD cbdata, heim_config_section ** parent)
 | 
						|
{
 | 
						|
    char                *reg_string = NULL;
 | 
						|
    heim_config_section *value;
 | 
						|
    heim_error_code     code = 0;
 | 
						|
 | 
						|
    reg_string = heim_parse_reg_value_as_string(context, key, valuename, type, cbdata);
 | 
						|
 | 
						|
    if (reg_string == NULL)
 | 
						|
        return HEIM_ERR_CONFIG_BADFORMAT;
 | 
						|
 | 
						|
    value = heim_config_get_entry(parent, valuename, heim_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;
 | 
						|
}
 | 
						|
 | 
						|
static heim_error_code
 | 
						|
parse_reg_values(heim_context context,
 | 
						|
                 HKEY key,
 | 
						|
                 heim_config_section ** parent)
 | 
						|
{
 | 
						|
    DWORD index;
 | 
						|
    LONG  rcode;
 | 
						|
 | 
						|
    for (index = 0; ; index ++) {
 | 
						|
        char    name[16385];
 | 
						|
        DWORD   cch = sizeof(name)/sizeof(name[0]);
 | 
						|
        DWORD   type;
 | 
						|
        DWORD   cbdata = 0;
 | 
						|
        heim_error_code code;
 | 
						|
 | 
						|
        rcode = RegEnumValue(key, index, name, &cch, NULL,
 | 
						|
                             &type, NULL, &cbdata);
 | 
						|
        if (rcode != ERROR_SUCCESS)
 | 
						|
            break;
 | 
						|
 | 
						|
        if (cbdata == 0)
 | 
						|
            continue;
 | 
						|
 | 
						|
        code = parse_reg_value(context, key, name, type, cbdata, parent);
 | 
						|
        if (code != 0)
 | 
						|
            return code;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static heim_error_code
 | 
						|
parse_reg_subkeys(heim_context context,
 | 
						|
                  HKEY key,
 | 
						|
                  heim_config_section ** parent)
 | 
						|
{
 | 
						|
    DWORD index;
 | 
						|
    LONG  rcode;
 | 
						|
 | 
						|
    for (index = 0; ; index ++) {
 | 
						|
        HKEY    subkey = NULL;
 | 
						|
        char    name[256];
 | 
						|
        DWORD   cch = sizeof(name)/sizeof(name[0]);
 | 
						|
        heim_config_section     *section = NULL;
 | 
						|
        heim_error_code         code;
 | 
						|
 | 
						|
        rcode = RegEnumKeyEx(key, index, name, &cch, NULL, NULL, NULL, NULL);
 | 
						|
        if (rcode != ERROR_SUCCESS)
 | 
						|
            break;
 | 
						|
 | 
						|
        rcode = RegOpenKeyEx(key, name, 0, KEY_READ, &subkey);
 | 
						|
        if (rcode != ERROR_SUCCESS)
 | 
						|
            continue;
 | 
						|
 | 
						|
        section = heim_config_get_entry(parent, name, heim_config_list);
 | 
						|
        if (section == NULL) {
 | 
						|
            RegCloseKey(subkey);
 | 
						|
            return ENOMEM;
 | 
						|
        }
 | 
						|
 | 
						|
        code = parse_reg_values(context, subkey, §ion->u.list);
 | 
						|
        if (code) {
 | 
						|
            RegCloseKey(subkey);
 | 
						|
            return code;
 | 
						|
        }
 | 
						|
 | 
						|
        code = parse_reg_subkeys(context, subkey, §ion->u.list);
 | 
						|
        if (code) {
 | 
						|
            RegCloseKey(subkey);
 | 
						|
            return code;
 | 
						|
        }
 | 
						|
 | 
						|
        RegCloseKey(subkey);
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static heim_error_code
 | 
						|
parse_reg_root(heim_context context,
 | 
						|
               HKEY key,
 | 
						|
               heim_config_section ** parent)
 | 
						|
{
 | 
						|
    heim_config_section *libdefaults = NULL;
 | 
						|
    heim_error_code     code = 0;
 | 
						|
 | 
						|
    libdefaults = heim_config_get_entry(parent, "libdefaults", heim_config_list);
 | 
						|
    if (libdefaults == NULL)
 | 
						|
        return heim_enomem(context);
 | 
						|
 | 
						|
    code = parse_reg_values(context, key, &libdefaults->u.list);
 | 
						|
    if (code)
 | 
						|
        return code;
 | 
						|
 | 
						|
    return parse_reg_subkeys(context, key, parent);
 | 
						|
}
 | 
						|
 | 
						|
static heim_error_code
 | 
						|
load_config_from_regpath(heim_context context,
 | 
						|
                         HKEY hk_root,
 | 
						|
                         const char* key_path,
 | 
						|
                         heim_config_section ** res)
 | 
						|
{
 | 
						|
    HKEY            key  = NULL;
 | 
						|
    LONG            rcode;
 | 
						|
    heim_error_code code = 0;
 | 
						|
 | 
						|
    rcode = RegOpenKeyEx(hk_root, key_path, 0, KEY_READ, &key);
 | 
						|
    if (rcode == ERROR_SUCCESS) {
 | 
						|
        code = parse_reg_root(context, key, res);
 | 
						|
        RegCloseKey(key);
 | 
						|
        key = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return code;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Load configuration from registry
 | 
						|
 *
 | 
						|
 * The registry keys 'HKCU\Software\Heimdal' and
 | 
						|
 * 'HKLM\Software\Heimdal' are treated as krb5.conf files.  Each
 | 
						|
 * registry key corresponds to a configuration section (or bound list)
 | 
						|
 * and each value in a registry key is treated as a bound value.  The
 | 
						|
 * set of values that are directly under the Heimdal key are treated
 | 
						|
 * as if they were defined in the [libdefaults] section.
 | 
						|
 *
 | 
						|
 * @see parse_reg_value() for details about how each type of value is handled.
 | 
						|
 */
 | 
						|
heim_error_code
 | 
						|
heim_load_config_from_registry(heim_context context,
 | 
						|
                               const char *path0,
 | 
						|
                               const char *path1,
 | 
						|
                               heim_config_section **res)
 | 
						|
{
 | 
						|
    heim_error_code code;
 | 
						|
 | 
						|
    if (!path0 && !path1)
 | 
						|
        return EINVAL;
 | 
						|
 | 
						|
    if (path0) {
 | 
						|
        code = load_config_from_regpath(context, HKEY_LOCAL_MACHINE,
 | 
						|
                                        path0, res);
 | 
						|
        if (code)
 | 
						|
            return code;
 | 
						|
    }
 | 
						|
 | 
						|
    if (path1) {
 | 
						|
        code = load_config_from_regpath(context, HKEY_LOCAL_MACHINE,
 | 
						|
                                        path1, res);
 | 
						|
        if (code)
 | 
						|
            return code;
 | 
						|
    }
 | 
						|
 | 
						|
    if (path0) {
 | 
						|
        code = load_config_from_regpath(context, HKEY_CURRENT_USER,
 | 
						|
                                        path0, res);
 | 
						|
        if (code)
 | 
						|
            return code;
 | 
						|
    }
 | 
						|
 | 
						|
    if (path0) {
 | 
						|
        code = load_config_from_regpath(context, HKEY_CURRENT_USER,
 | 
						|
                                        path1, res);
 | 
						|
        if (code)
 | 
						|
            return code;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 |