/source3/libsmb/conncache.c

https://github.com/theresahalloran/samba-tool-group-doc · C · 226 lines · 106 code · 28 blank · 92 comment · 23 complexity · 4473b4bd5d103fc4b798f0883d4ab070 MD5 · raw file

  1. /*
  2. Unix SMB/CIFS implementation.
  3. Winbind daemon connection manager
  4. Copyright (C) Tim Potter 2001
  5. Copyright (C) Andrew Bartlett 2002
  6. Copyright (C) Gerald (Jerry) Carter 2003
  7. Copyright (C) Marc VanHeyningen 2008
  8. Copyright (C) Volker Lendecke 2009
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 3 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "includes.h"
  21. /**
  22. * @file
  23. * Negative connection cache implemented in terms of gencache API
  24. *
  25. * The negative connection cache stores names of servers which have
  26. * been unresponsive so that we don't waste time repeatedly trying
  27. * to contact them. It used to use an in-memory linked list, but
  28. * this limited its utility to a single process
  29. */
  30. /**
  31. * Marshalls the domain and server name into the key for the gencache
  32. * record
  33. *
  34. * @param[in] domain required
  35. * @param[in] server may be a FQDN or an IP address
  36. * @return the resulting string, which the caller is responsible for
  37. * SAFE_FREE()ing
  38. * @retval NULL returned on error
  39. */
  40. static char *negative_conn_cache_keystr(const char *domain, const char *server)
  41. {
  42. char *keystr = NULL;
  43. if (domain == NULL) {
  44. return NULL;
  45. }
  46. if (server == NULL)
  47. server = "";
  48. keystr = talloc_asprintf(talloc_tos(), "NEG_CONN_CACHE/%s,%s",
  49. domain, server);
  50. if (keystr == NULL) {
  51. DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
  52. }
  53. return keystr;
  54. }
  55. /**
  56. * Marshalls the NT status into a printable value field for the gencache
  57. * record
  58. *
  59. * @param[in] status
  60. * @return the resulting string, which the caller is responsible for
  61. * SAFE_FREE()ing
  62. * @retval NULL returned on error
  63. */
  64. static char *negative_conn_cache_valuestr(NTSTATUS status)
  65. {
  66. char *valuestr = NULL;
  67. valuestr = talloc_asprintf(talloc_tos(), "%x", NT_STATUS_V(status));
  68. if (valuestr == NULL) {
  69. DEBUG(0, ("negative_conn_cache_valuestr: malloc error\n"));
  70. }
  71. return valuestr;
  72. }
  73. /**
  74. * Un-marshalls the NT status from a printable field for the gencache
  75. * record
  76. *
  77. * @param[in] value The value field from the record
  78. * @return the decoded NT status
  79. * @retval NT_STATUS_OK returned on error
  80. */
  81. static NTSTATUS negative_conn_cache_valuedecode(const char *value)
  82. {
  83. unsigned int v = NT_STATUS_V(NT_STATUS_INTERNAL_ERROR);
  84. if (value == NULL) {
  85. return NT_STATUS_INTERNAL_ERROR;
  86. }
  87. if (sscanf(value, "%x", &v) != 1) {
  88. DEBUG(0, ("negative_conn_cache_valuedecode: unable to parse "
  89. "value field '%s'\n", value));
  90. }
  91. return NT_STATUS(v);
  92. }
  93. /**
  94. * Function passed to gencache_iterate to remove any matching items
  95. * from the list
  96. *
  97. * @param[in] key Key to the record found and to be deleted
  98. * @param[in] value Value to the record (ignored)
  99. * @param[in] timeout Timeout remaining for the record (ignored)
  100. * @param[in] dptr Handle for passing additional data (ignored)
  101. */
  102. static void delete_matches(const char *key, const char *value,
  103. time_t timeout, void *dptr)
  104. {
  105. gencache_del(key);
  106. }
  107. /**
  108. * Checks for a given domain/server record in the negative cache
  109. *
  110. * @param[in] domain
  111. * @param[in] server may be either a FQDN or an IP address
  112. * @return The cached failure status
  113. * @retval NT_STATUS_OK returned if no record is found or an error occurs
  114. */
  115. NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
  116. {
  117. NTSTATUS result = NT_STATUS_OK;
  118. char *key = NULL;
  119. char *value = NULL;
  120. key = negative_conn_cache_keystr(domain, server);
  121. if (key == NULL)
  122. goto done;
  123. if (gencache_get(key, &value, NULL))
  124. result = negative_conn_cache_valuedecode(value);
  125. done:
  126. DEBUG(9,("check_negative_conn_cache returning result %d for domain %s "
  127. "server %s\n", NT_STATUS_V(result), domain, server));
  128. TALLOC_FREE(key);
  129. SAFE_FREE(value);
  130. return result;
  131. }
  132. /**
  133. * Add an entry to the failed connection cache
  134. *
  135. * @param[in] domain
  136. * @param[in] server may be a FQDN or an IP addr in printable form
  137. * @param[in] result error to cache; must not be NT_STATUS_OK
  138. */
  139. void add_failed_connection_entry(const char *domain, const char *server,
  140. NTSTATUS result)
  141. {
  142. char *key = NULL;
  143. char *value = NULL;
  144. if (NT_STATUS_IS_OK(result)) {
  145. /* Nothing failed here */
  146. return;
  147. }
  148. key = negative_conn_cache_keystr(domain, server);
  149. if (key == NULL) {
  150. DEBUG(0, ("add_failed_connection_entry: key creation error\n"));
  151. goto done;
  152. }
  153. value = negative_conn_cache_valuestr(result);
  154. if (value == NULL) {
  155. DEBUG(0, ("add_failed_connection_entry: value creation error\n"));
  156. goto done;
  157. }
  158. if (gencache_set(key, value,
  159. time(NULL) + FAILED_CONNECTION_CACHE_TIMEOUT))
  160. DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
  161. "to failed conn cache\n", domain, server ));
  162. else
  163. DEBUG(1,("add_failed_connection_entry: failed to add "
  164. "domain %s (%s) to failed conn cache\n",
  165. domain, server));
  166. done:
  167. TALLOC_FREE(key);
  168. TALLOC_FREE(value);
  169. return;
  170. }
  171. /**
  172. * Deletes all records for a specified domain from the negative connection
  173. * cache
  174. *
  175. * @param[in] domain String to match against domain portion of keys, or "*"
  176. * to match all domains
  177. */
  178. void flush_negative_conn_cache_for_domain(const char *domain)
  179. {
  180. char *key_pattern = NULL;
  181. key_pattern = negative_conn_cache_keystr(domain,"*");
  182. if (key_pattern == NULL) {
  183. DEBUG(0, ("flush_negative_conn_cache_for_domain: "
  184. "key creation error\n"));
  185. goto done;
  186. }
  187. gencache_iterate(delete_matches, NULL, key_pattern);
  188. DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
  189. domain));
  190. done:
  191. TALLOC_FREE(key_pattern);
  192. return;
  193. }