registry.c 6.1 KB

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