registry.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Implement convenience wrappers on the awkward low-level functions
  3. * for accessing the Windows registry.
  4. */
  5. #include "putty.h"
  6. HKEY open_regkey_fn(bool create, HKEY hk, const char *path, ...)
  7. {
  8. HKEY toret = NULL;
  9. bool hk_needs_close = false;
  10. va_list ap;
  11. va_start(ap, path);
  12. for (; path; path = va_arg(ap, const char *)) {
  13. HKEY hk_sub = NULL;
  14. LONG status;
  15. if (create)
  16. status = RegCreateKeyEx(
  17. hk, path, 0, NULL, REG_OPTION_NON_VOLATILE,
  18. KEY_READ | KEY_WRITE, NULL, &hk_sub, NULL);
  19. else
  20. status = RegOpenKeyEx(
  21. hk, path, 0, KEY_READ | KEY_WRITE, &hk_sub);
  22. if (status != ERROR_SUCCESS)
  23. goto out;
  24. if (hk_needs_close)
  25. RegCloseKey(hk);
  26. hk = hk_sub;
  27. hk_needs_close = true;
  28. }
  29. toret = hk;
  30. hk = NULL;
  31. hk_needs_close = false;
  32. out:
  33. va_end(ap);
  34. if (hk_needs_close)
  35. RegCloseKey(hk);
  36. return toret;
  37. }
  38. void close_regkey(HKEY key)
  39. {
  40. RegCloseKey(key);
  41. }
  42. void del_regkey(HKEY key, const char *name)
  43. {
  44. RegDeleteKey(key, name);
  45. }
  46. char *enum_regkey(HKEY key, int index)
  47. {
  48. size_t regbuf_size = MAX_PATH + 1;
  49. char *regbuf = snewn(regbuf_size, char);
  50. while (1) {
  51. LONG status = RegEnumKey(key, index, regbuf, regbuf_size);
  52. if (status == ERROR_SUCCESS)
  53. return regbuf;
  54. if (status != ERROR_MORE_DATA) {
  55. sfree(regbuf);
  56. return NULL;
  57. }
  58. sgrowarray(regbuf, regbuf_size, regbuf_size);
  59. }
  60. }
  61. bool get_reg_dword(HKEY key, const char *name, DWORD *out)
  62. {
  63. DWORD type, size;
  64. size = sizeof(*out);
  65. if (RegQueryValueEx(key, name, 0, &type,
  66. (BYTE *)out, &size) != ERROR_SUCCESS ||
  67. size != sizeof(*out) || type != REG_DWORD)
  68. return false;
  69. else
  70. return true;
  71. }
  72. bool put_reg_dword(HKEY key, const char *name, DWORD value)
  73. {
  74. return RegSetValueEx(key, name, 0, REG_DWORD, (CONST BYTE *) &value,
  75. sizeof(value)) == ERROR_SUCCESS;
  76. }
  77. char *get_reg_sz(HKEY key, const char *name)
  78. {
  79. DWORD type, size;
  80. if (RegQueryValueEx(key, name, 0, &type, NULL,
  81. &size) != ERROR_SUCCESS || type != REG_SZ)
  82. return NULL; /* not a string */
  83. size_t allocsize = size+1; /* allow for an extra NUL if needed */
  84. char *toret = snewn(allocsize, char);
  85. if (RegQueryValueEx(key, name, 0, &type, (BYTE *)toret,
  86. &size) != ERROR_SUCCESS || type != REG_SZ) {
  87. sfree(toret);
  88. return NULL;
  89. }
  90. assert(size < allocsize);
  91. toret[size] = '\0'; /* add an extra NUL in case RegQueryValueEx
  92. * didn't supply one */
  93. return toret;
  94. }
  95. bool put_reg_sz(HKEY key, const char *name, const char *str)
  96. {
  97. /* You have to store the trailing NUL as well */
  98. return RegSetValueEx(key, name, 0, REG_SZ, (CONST BYTE *)str,
  99. 1 + strlen(str)) == ERROR_SUCCESS;
  100. }
  101. /*
  102. * REG_MULTI_SZ items are stored as a concatenation of NUL-terminated
  103. * strings, terminated in turn with an empty string, i.e. a second
  104. * consecutive NUL.
  105. *
  106. * We represent these in their storage format, as a strbuf - but
  107. * *without* the second consecutive NUL.
  108. *
  109. * So you can build up a new MULTI_SZ value in a strbuf by calling
  110. * put_asciz once per output string and then put_reg_multi_sz; and you
  111. * can consume one by initialising a BinarySource to the result of
  112. * get_reg_multi_sz, and then calling get_asciz on it and assuming
  113. * that !get_err(src) means you have a real output string.
  114. *
  115. * Also, calling strbuf_to_str on one of these will give you back a
  116. * bare 'char *' with the same double-NUL termination, to pass back to
  117. * a caller.
  118. */
  119. strbuf *get_reg_multi_sz(HKEY key, const char *name)
  120. {
  121. DWORD type, size;
  122. if (RegQueryValueEx(key, name, 0, &type, NULL,
  123. &size) != ERROR_SUCCESS || type != REG_MULTI_SZ)
  124. return NULL; /* not a string */
  125. strbuf *toret = strbuf_new();
  126. void *ptr = strbuf_append(toret, (size_t)size + 2);
  127. if (RegQueryValueEx(key, name, 0, &type, (BYTE *)ptr,
  128. &size) != ERROR_SUCCESS || type != REG_MULTI_SZ) {
  129. strbuf_free(toret);
  130. return NULL;
  131. }
  132. strbuf_shrink_to(toret, size);
  133. /* Ensure we end with exactly one \0 */
  134. while (strbuf_chomp(toret, '\0'));
  135. put_byte(toret, '\0');
  136. return toret;
  137. }
  138. bool put_reg_multi_sz(HKEY key, const char *name, strbuf *str)
  139. {
  140. /*
  141. * Of course, to write our string list into the registry, we _do_
  142. * have to include both trailing NULs. But this is easy, because a
  143. * strbuf is also designed to hold a single string and make it
  144. * conveniently accessible in NUL-terminated form, so it stores a
  145. * NUL in its buffer just beyond its formal length. So we just
  146. * include that extra byte in the data we write.
  147. */
  148. return RegSetValueEx(key, name, 0, REG_MULTI_SZ, (CONST BYTE *)str->s,
  149. str->len + 1) == ERROR_SUCCESS;
  150. }
  151. char *get_reg_sz_simple(HKEY key, const char *name, const char *leaf)
  152. {
  153. HKEY subkey = open_regkey(false, key, name);
  154. if (!subkey)
  155. return NULL;
  156. char *toret = get_reg_sz(subkey, leaf);
  157. RegCloseKey(subkey);
  158. return toret;
  159. }