1 /***********************************************************************
2 * Copyright (c) 2010, Secure Endpoints Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 **********************************************************************/
35 #error config_reg.c is only for Windows
41 #define MAX_DWORD 0xFFFFFFFF
45 * Store a string as a registry value of the specified type
47 * The following registry types are handled:
49 * - REG_DWORD: The string is converted to a number.
51 * - REG_SZ: The string is stored as is.
53 * - REG_EXPAND_SZ: The string is stored as is.
57 * . If a separator is specified, the input string is broken
58 * up into multiple strings and stored as a multi-sz.
60 * . If no separator is provided, the input string is stored
65 * . If the string is all numeric, it will be stored as a
68 * . Otherwise, the string is stored as a REG_SZ.
70 * Other types are rejected.
72 * If cb_data is MAX_DWORD, the string pointed to by data must be nul-terminated
73 * otherwise a buffer overrun will occur.
75 * @param [in]valuename Name of the registry value to be modified or created
76 * @param [in]type Type of the value. REG_NONE if unknown
77 * @param [in]data The input string to be stored in the registry.
78 * @param [in]cb_data Size of the input string in bytes. MAX_DWORD if unknown.
79 * @param [in]separator Separator character for parsing strings.
81 * @retval 0 if success or non-zero on error.
82 * If non-zero is returned, an error message has been set using
83 * heim_set_error_message().
87 heim_store_string_to_reg_value(heim_context context
,
88 HKEY key
, const char *valuename
,
89 DWORD type
, const char *data
, DWORD cb_data
,
90 const char *separator
)
94 BYTE static_buffer
[16384];
99 heim_set_error_message(context
, 0,
100 "'data' must not be NULL");
104 if (cb_data
== MAX_DWORD
)
106 cb_data
= (DWORD
)strlen(data
) + 1;
108 else if ((type
== REG_MULTI_SZ
&& cb_data
>= sizeof(static_buffer
) - 1) ||
109 cb_data
>= sizeof(static_buffer
))
112 heim_set_error_message(context
, 0, "cb_data too big");
115 else if (data
[cb_data
-1] != '\0')
117 memcpy(static_buffer
, data
, cb_data
);
118 static_buffer
[cb_data
++] = '\0';
119 if (type
== REG_MULTI_SZ
)
120 static_buffer
[cb_data
++] = '\0';
121 data
= static_buffer
;
124 if (type
== REG_NONE
)
127 * If input is all numeric, convert to DWORD and save as REG_DWORD.
128 * Otherwise, store as REG_SZ.
130 if ( StrToIntExA( data
, STIF_SUPPORT_HEX
, &dwData
) )
141 rcode
= RegSetValueEx(key
, valuename
, 0, type
, data
, cb_data
);
145 heim_set_error_message(context
, 0,
146 "Unexpected error when setting registry value %s gle 0x%x",
153 if (separator
&& *separator
)
157 if (data
!= static_buffer
)
158 static_buffer
[cb_data
++] = '\0';
160 for ( cp
= static_buffer
; cp
< static_buffer
+cb_data
; cp
++)
162 if (*cp
== *separator
)
166 rcode
= RegSetValueEx(key
, valuename
, 0, type
, data
, cb_data
);
170 heim_set_error_message(context
, 0,
171 "Unexpected error when setting registry value %s gle 0x%x",
179 if ( !StrToIntExA( data
, STIF_SUPPORT_HEX
, &dwData
) )
182 heim_set_error_message(context
, 0,
183 "Unexpected error when parsing %s as number gle 0x%x",
188 rcode
= RegSetValueEx(key
, valuename
, 0, type
, (BYTE
*)&dwData
, sizeof(DWORD
));
192 heim_set_error_message(context
, 0,
193 "Unexpected error when setting registry value %s gle 0x%x",
207 * Parse a registry value as a string
209 * @see heim_parse_reg_value_as_multi_string()
212 heim_parse_reg_value_as_string(heim_context context
,
213 HKEY key
, const char * valuename
,
214 DWORD type
, DWORD cb_data
)
216 return heim_parse_reg_value_as_multi_string(context
, key
, valuename
,
221 * Parse a registry value as a multi string
223 * The following registry value types are handled:
225 * - REG_DWORD: The decimal string representation is used as the
228 * - REG_SZ: The string is used as-is.
230 * - REG_EXPAND_SZ: Environment variables in the string are expanded
231 * and the result is used as the value.
233 * - REG_MULTI_SZ: The list of strings is concatenated using the
234 * separator. No quoting is performed.
236 * Any other value type is rejected.
238 * @param [in]valuename Name of the registry value to be queried
239 * @param [in]type Type of the value. REG_NONE if unknown
240 * @param [in]cbdata Size of value. 0 if unknown.
241 * @param [in]separator Separator character for concatenating strings.
243 * @a type and @a cbdata are only considered valid if both are
246 * @retval The registry value string, or NULL if there was an error.
247 * If NULL is returned, an error message has been set using
248 * heim_set_error_message().
251 heim_parse_reg_value_as_multi_string(heim_context context
,
252 HKEY key
, const char * valuename
,
253 DWORD type
, DWORD cb_data
, char *separator
)
255 LONG rcode
= ERROR_MORE_DATA
;
257 BYTE static_buffer
[16384];
258 BYTE
*pbuffer
= &static_buffer
[0];
259 DWORD cb_alloc
= sizeof(static_buffer
);
260 char *ret_string
= NULL
;
262 /* If we know a type and cb_data from a previous call to
263 * RegEnumValue(), we use it. Otherwise we use the
264 * static_buffer[] and query directly. We do this to minimize the
265 * number of queries. */
267 if (type
== REG_NONE
|| cb_data
== 0) {
269 pbuffer
= &static_buffer
[0];
270 cb_alloc
= cb_data
= sizeof(static_buffer
);
271 rcode
= RegQueryValueExA(key
, valuename
, NULL
, &type
, pbuffer
, &cb_data
);
273 if (rcode
== ERROR_SUCCESS
&&
276 type
!= REG_EXPAND_SZ
) || cb_data
+ 1 <= sizeof(static_buffer
)) &&
278 (type
!= REG_MULTI_SZ
|| cb_data
+ 2 <= sizeof(static_buffer
)))
281 if (rcode
!= ERROR_MORE_DATA
&& rcode
!= ERROR_SUCCESS
)
285 /* Either we don't have the data or we aren't sure of the size
286 * (due to potentially missing terminating NULs). */
290 if (cb_data
!= sizeof(DWORD
)) {
292 heim_set_error_message(context
, 0,
293 "Unexpected size while reading registry value %s",
302 if (rcode
== ERROR_SUCCESS
&& cb_data
> 0 && pbuffer
[cb_data
- 1] == '\0')
305 cb_data
+= sizeof(char); /* Accout for potential missing NUL
311 if (rcode
== ERROR_SUCCESS
&& cb_data
> 0 && pbuffer
[cb_data
- 1] == '\0' &&
312 (cb_data
== 1 || pbuffer
[cb_data
- 2] == '\0'))
315 cb_data
+= sizeof(char) * 2; /* Potential missing double NUL
321 heim_set_error_message(context
, 0,
322 "Unexpected type while reading registry value %s",
327 if (cb_data
<= sizeof(static_buffer
))
328 pbuffer
= &static_buffer
[0];
330 pbuffer
= malloc(cb_data
);
336 rcode
= RegQueryValueExA(key
, valuename
, NULL
, NULL
, pbuffer
, &cb_data
);
338 if (rcode
!= ERROR_SUCCESS
) {
340 /* This can potentially be from a race condition. I.e. some
341 * other process or thread went and modified the registry
342 * value between the time we queried its size and queried for
343 * its value. Ideally we would retry the query in a loop. */
346 heim_set_error_message(context
, 0,
347 "Unexpected error while reading registry value %s",
352 if (cb_data
> cb_alloc
|| cb_data
== 0) {
354 heim_set_error_message(context
, 0,
355 "Unexpected size while reading registry value %s",
363 asprintf(&ret_string
, "%d", *((DWORD
*) pbuffer
));
368 char * str
= (char *) pbuffer
;
370 if (str
[cb_data
- 1] != '\0') {
371 if (cb_data
< cb_alloc
)
377 if (pbuffer
!= static_buffer
) {
378 ret_string
= (char *) pbuffer
;
381 ret_string
= strdup((char *) pbuffer
);
388 char *str
= (char *) pbuffer
;
389 char expsz
[32768]; /* Size of output buffer for
390 * ExpandEnvironmentStrings() is
393 if (str
[cb_data
- 1] != '\0') {
394 if (cb_data
< cb_alloc
)
400 if (ExpandEnvironmentStrings(str
, expsz
, sizeof(expsz
)/sizeof(char)) != 0) {
401 ret_string
= strdup(expsz
);
404 heim_set_error_message(context
, 0,
405 "Overflow while expanding environment strings "
406 "for registry value %s", valuename
);
413 char * str
= (char *) pbuffer
;
416 str
[cb_alloc
- 1] = '\0';
417 str
[cb_alloc
- 2] = '\0';
419 for (iter
= str
; *iter
;) {
420 size_t len
= strlen(iter
);
424 *iter
++ = *separator
;
429 if (pbuffer
!= static_buffer
) {
433 ret_string
= strdup(str
);
440 heim_set_error_message(context
, 0,
441 "Unexpected type while reading registry value %s",
446 if (pbuffer
!= static_buffer
&& pbuffer
!= NULL
)
453 * Parse a registry value as a configuration value
455 * @see parse_reg_value_as_string()
457 static heim_error_code
458 parse_reg_value(heim_context context
,
459 HKEY key
, const char * valuename
,
460 DWORD type
, DWORD cbdata
, heim_config_section
** parent
)
462 char *reg_string
= NULL
;
463 heim_config_section
*value
;
464 heim_error_code code
= 0;
466 reg_string
= heim_parse_reg_value_as_string(context
, key
, valuename
, type
, cbdata
);
468 if (reg_string
== NULL
)
469 return HEIM_ERR_CONFIG_BADFORMAT
;
471 value
= heim_config_get_entry(parent
, valuename
, heim_config_string
);
477 if (value
->u
.string
!= NULL
)
478 free(value
->u
.string
);
480 value
->u
.string
= reg_string
;
484 if (reg_string
!= NULL
)
490 static heim_error_code
491 parse_reg_values(heim_context context
,
493 heim_config_section
** parent
)
498 for (index
= 0; ; index
++) {
500 DWORD cch
= sizeof(name
)/sizeof(name
[0]);
503 heim_error_code code
;
505 rcode
= RegEnumValue(key
, index
, name
, &cch
, NULL
,
506 &type
, NULL
, &cbdata
);
507 if (rcode
!= ERROR_SUCCESS
)
513 code
= parse_reg_value(context
, key
, name
, type
, cbdata
, parent
);
521 static heim_error_code
522 parse_reg_subkeys(heim_context context
,
524 heim_config_section
** parent
)
529 for (index
= 0; ; index
++) {
532 DWORD cch
= sizeof(name
)/sizeof(name
[0]);
533 heim_config_section
*section
= NULL
;
534 heim_error_code code
;
536 rcode
= RegEnumKeyEx(key
, index
, name
, &cch
, NULL
, NULL
, NULL
, NULL
);
537 if (rcode
!= ERROR_SUCCESS
)
540 rcode
= RegOpenKeyEx(key
, name
, 0, KEY_READ
, &subkey
);
541 if (rcode
!= ERROR_SUCCESS
)
544 section
= heim_config_get_entry(parent
, name
, heim_config_list
);
545 if (section
== NULL
) {
550 code
= parse_reg_values(context
, subkey
, §ion
->u
.list
);
556 code
= parse_reg_subkeys(context
, subkey
, §ion
->u
.list
);
568 static heim_error_code
569 parse_reg_root(heim_context context
,
571 heim_config_section
** parent
)
573 heim_config_section
*libdefaults
= NULL
;
574 heim_error_code code
= 0;
576 libdefaults
= heim_config_get_entry(parent
, "libdefaults", heim_config_list
);
577 if (libdefaults
== NULL
)
578 return heim_enomem(context
);
580 code
= parse_reg_values(context
, key
, &libdefaults
->u
.list
);
584 return parse_reg_subkeys(context
, key
, parent
);
587 static heim_error_code
588 load_config_from_regpath(heim_context context
,
590 const char* key_path
,
591 heim_config_section
** res
)
595 heim_error_code code
= 0;
597 rcode
= RegOpenKeyEx(hk_root
, key_path
, 0, KEY_READ
, &key
);
598 if (rcode
== ERROR_SUCCESS
) {
599 code
= parse_reg_root(context
, key
, res
);
608 * Load configuration from registry
610 * The registry keys 'HKCU\Software\Heimdal' and
611 * 'HKLM\Software\Heimdal' are treated as krb5.conf files. Each
612 * registry key corresponds to a configuration section (or bound list)
613 * and each value in a registry key is treated as a bound value. The
614 * set of values that are directly under the Heimdal key are treated
615 * as if they were defined in the [libdefaults] section.
617 * @see parse_reg_value() for details about how each type of value is handled.
620 heim_load_config_from_registry(heim_context context
,
623 heim_config_section
**res
)
625 heim_error_code code
;
627 if (!path0
&& !path1
)
631 code
= load_config_from_regpath(context
, HKEY_LOCAL_MACHINE
,
638 code
= load_config_from_regpath(context
, HKEY_LOCAL_MACHINE
,
645 code
= load_config_from_regpath(context
, HKEY_CURRENT_USER
,
652 code
= load_config_from_regpath(context
, HKEY_CURRENT_USER
,