Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2016 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
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 :
21 : #include <talloc.h>
22 : #include <tevent.h>
23 : #include <dhash.h>
24 :
25 : #include "sbus/sssd_dbus.h"
26 : #include "providers/data_provider/dp_private.h"
27 : #include "providers/backend.h"
28 : #include "util/dlinklist.h"
29 : #include "util/sss_utf8.h"
30 : #include "util/util.h"
31 :
32 : static int
33 8 : dp_sbus_req_item_destructor(struct dp_sbus_req_item *item)
34 : {
35 8 : DLIST_REMOVE(item->parent->list, item);
36 :
37 8 : return 0;
38 : }
39 :
40 : static int
41 3 : dp_table_value_destructor(struct dp_table_value *value)
42 : {
43 : struct dp_sbus_req_item *next_item;
44 : struct dp_sbus_req_item *item;
45 :
46 3 : DEBUG(SSSDBG_TRACE_FUNC, "Removing [%s] from reply table\n", value->key);
47 :
48 3 : dp_req_table_del(value->table, value->key);
49 :
50 6 : for (item = value->list; item != NULL; item = next_item) {
51 3 : next_item = item->next;
52 3 : talloc_free(item);
53 : }
54 :
55 3 : return 0;
56 : }
57 :
58 : static struct dp_sbus_req_item *
59 8 : dp_sbus_req_item_new(struct dp_table_value *value,
60 : struct sbus_request *sbus_req)
61 : {
62 : struct dp_sbus_req_item *item;
63 :
64 : /* Attach to sbus_request so we ensure that this sbus_req is removed
65 : * from the list when it is unexpectedly freed, for example when
66 : * client connection is dropped. */
67 8 : item = talloc_zero(sbus_req, struct dp_sbus_req_item);
68 8 : if (item == NULL) {
69 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
70 0 : return NULL;
71 : }
72 :
73 8 : item->parent = value;
74 8 : item->sbus_req = sbus_req;
75 :
76 8 : talloc_set_destructor(item, dp_sbus_req_item_destructor);
77 :
78 8 : return item;
79 : }
80 :
81 4 : char *dp_req_table_key(TALLOC_CTX *mem_ctx,
82 : enum dp_targets target,
83 : enum dp_methods method,
84 : uint32_t dp_flags,
85 : const char *custom_part)
86 : {
87 4 : const char *str = custom_part == NULL ? "(null)" : custom_part;
88 :
89 4 : return talloc_asprintf(mem_ctx, "%u:%u:%#.4x:%s",
90 : target, method, dp_flags, str);
91 : }
92 :
93 4 : errno_t dp_req_table_init(TALLOC_CTX *mem_ctx, hash_table_t **_table)
94 : {
95 4 : return sss_hash_create(mem_ctx, 100, _table);
96 : }
97 :
98 16 : struct dp_table_value *dp_req_table_lookup(hash_table_t *table,
99 : const char *key)
100 : {
101 : hash_key_t hkey;
102 : hash_value_t hvalue;
103 : int hret;
104 :
105 16 : hkey.type = HASH_KEY_STRING;
106 16 : hkey.str = discard_const_p(char, key);
107 :
108 16 : hret = hash_lookup(table, &hkey, &hvalue);
109 16 : if (hret == HASH_ERROR_KEY_NOT_FOUND) {
110 6 : return NULL;
111 10 : } else if (hret != HASH_SUCCESS) {
112 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to search hash table [%d]\n", hret);
113 0 : return NULL;
114 : }
115 :
116 10 : return hvalue.ptr;
117 : }
118 :
119 3 : static errno_t dp_req_table_new_item(hash_table_t *table,
120 : const char *key,
121 : struct tevent_req *req,
122 : struct sbus_request *sbus_req)
123 : {
124 : hash_key_t hkey;
125 : hash_value_t hvalue;
126 : struct dp_table_value *table_value;
127 : errno_t ret;
128 : int hret;
129 :
130 : /* Attach it to request. */
131 3 : table_value = talloc_zero(req, struct dp_table_value);
132 3 : if (table_value == NULL) {
133 0 : return ENOMEM;
134 : }
135 :
136 3 : table_value->table = table;
137 3 : table_value->key = talloc_strdup(table_value, key);
138 3 : if (table_value->key == NULL) {
139 0 : ret = ENOMEM;
140 0 : goto done;
141 : }
142 :
143 3 : table_value->req = req;
144 3 : table_value->list = dp_sbus_req_item_new(table_value, sbus_req);
145 3 : if (table_value->list == NULL) {
146 0 : ret = ENOMEM;
147 0 : goto done;
148 : }
149 :
150 3 : talloc_set_destructor(table_value, dp_table_value_destructor);
151 :
152 3 : hkey.type = HASH_KEY_STRING;
153 3 : hkey.str = discard_const_p(char, key);
154 :
155 3 : hvalue.type = HASH_VALUE_PTR;
156 3 : hvalue.ptr = table_value;
157 :
158 3 : hret = hash_enter(table, &hkey, &hvalue);
159 3 : if (hret != HASH_SUCCESS) {
160 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to enter value into hash table "
161 : "[%d]\n", hret);
162 0 : ret = EIO;
163 0 : goto done;
164 : }
165 :
166 3 : ret = EOK;
167 :
168 : done:
169 3 : if (ret != EOK) {
170 0 : talloc_free(table_value);
171 : }
172 :
173 3 : return ret;
174 : }
175 :
176 5 : static errno_t dp_req_table_mod_item(hash_table_t *table,
177 : struct dp_table_value *table_value,
178 : struct sbus_request *sbus_req)
179 : {
180 : struct dp_sbus_req_item *item;
181 :
182 5 : item = dp_sbus_req_item_new(table_value, sbus_req);
183 5 : if (item == NULL) {
184 0 : return ENOMEM;
185 : }
186 :
187 5 : DLIST_ADD(table_value->list, item);
188 :
189 5 : return EOK;
190 : }
191 :
192 8 : errno_t dp_req_table_add(hash_table_t *table,
193 : const char *key,
194 : struct tevent_req *req,
195 : struct sbus_request *sbus_req)
196 : {
197 : struct dp_table_value *table_value;
198 :
199 8 : if (sbus_req == NULL) {
200 0 : DEBUG(SSSDBG_CRIT_FAILURE, "SBUS request cannot be NULL\n");
201 0 : return EINVAL;
202 : }
203 :
204 8 : table_value = dp_req_table_lookup(table, key);
205 8 : if (table_value == NULL) {
206 3 : if (req == NULL) {
207 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Tevent request cannot be NULL\n");
208 0 : return EINVAL;
209 : }
210 :
211 3 : return dp_req_table_new_item(table, key, req, sbus_req);
212 : }
213 :
214 5 : return dp_req_table_mod_item(table, table_value, sbus_req);
215 : }
216 :
217 7 : void dp_req_table_del(hash_table_t *table,
218 : const char *key)
219 : {
220 : hash_key_t hkey;
221 : int hret;
222 :
223 7 : if (table == NULL || key == NULL) {
224 0 : return;
225 : }
226 :
227 7 : hkey.type = HASH_KEY_STRING;
228 7 : hkey.str = discard_const_p(char, key);
229 :
230 7 : hret = hash_delete(table, &hkey);
231 7 : if (hret != HASH_SUCCESS && hret != HASH_ERROR_KEY_NOT_FOUND) {
232 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to remove key from table [%d]\n",
233 : hret);
234 : }
235 :
236 7 : return;
237 : }
238 :
239 0 : void dp_req_table_del_and_free(hash_table_t *table,
240 : const char *key)
241 : {
242 : struct dp_table_value *value;
243 :
244 0 : value = dp_req_table_lookup(table, key);
245 0 : if (value == NULL) {
246 : /* We're done here. */
247 0 : return;
248 : }
249 :
250 0 : dp_req_table_del(table, key);
251 0 : talloc_free(value);
252 :
253 0 : return;
254 : }
255 :
256 14 : bool dp_req_table_has_key(hash_table_t *table,
257 : const char *key)
258 : {
259 : hash_key_t hkey;
260 :
261 14 : hkey.type = HASH_KEY_STRING;
262 14 : hkey.str = discard_const_p(char, key);
263 :
264 14 : return hash_has_key(table, &hkey);
265 : }
|