Line data Source code
1 : /*
2 : SSSD
3 :
4 : SSS Client Responder, command parser
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
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 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 : #include <errno.h>
22 : #include "db/sysdb.h"
23 : #include "util/util.h"
24 : #include "responder/common/responder.h"
25 : #include "responder/common/responder_packet.h"
26 :
27 4 : int sss_cmd_send_error(struct cli_ctx *cctx, int err)
28 : {
29 : int ret;
30 :
31 : /* create response packet */
32 8 : ret = sss_packet_new(cctx->creq, 0,
33 4 : sss_packet_get_cmd(cctx->creq->in),
34 4 : &cctx->creq->out);
35 4 : if (ret != EOK) {
36 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create new packet: %d\n", ret);
37 0 : return ret;
38 : }
39 :
40 4 : sss_packet_set_error(cctx->creq->out, err);
41 4 : return EOK;
42 : }
43 :
44 0 : int sss_cmd_empty_packet(struct sss_packet *packet)
45 : {
46 : uint8_t *body;
47 : size_t blen;
48 : int ret;
49 :
50 0 : ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
51 0 : if (ret != EOK) return ret;
52 :
53 0 : sss_packet_get_body(packet, &body, &blen);
54 :
55 : /* num results */
56 0 : SAFEALIGN_SETMEM_UINT32(body, 0, NULL);
57 :
58 : /* reserved */
59 0 : SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
60 :
61 0 : return EOK;
62 : }
63 :
64 0 : int sss_cmd_send_empty(struct cli_ctx *cctx, TALLOC_CTX *freectx)
65 : {
66 : int ret;
67 :
68 : /* create response packet */
69 0 : ret = sss_packet_new(cctx->creq, 0,
70 0 : sss_packet_get_cmd(cctx->creq->in),
71 0 : &cctx->creq->out);
72 0 : if (ret != EOK) {
73 0 : return ret;
74 : }
75 :
76 0 : ret = sss_cmd_empty_packet(cctx->creq->out);
77 0 : if (ret != EOK) {
78 0 : return ret;
79 : }
80 :
81 0 : sss_packet_set_error(cctx->creq->out, EOK);
82 0 : sss_cmd_done(cctx, freectx);
83 0 : return EOK;
84 : }
85 :
86 0 : void sss_cmd_done(struct cli_ctx *cctx, void *freectx)
87 : {
88 : /* now that the packet is in place, unlock queue
89 : * making the event writable */
90 0 : TEVENT_FD_WRITEABLE(cctx->cfde);
91 :
92 : /* free all request related data through the talloc hierarchy */
93 0 : talloc_free(freectx);
94 0 : }
95 :
96 0 : int sss_cmd_get_version(struct cli_ctx *cctx)
97 : {
98 : uint8_t *req_body;
99 : size_t req_blen;
100 : uint8_t *body;
101 : size_t blen;
102 : int ret;
103 : uint32_t client_version;
104 : uint32_t protocol_version;
105 : int i;
106 : static struct cli_protocol_version *cli_protocol_version = NULL;
107 :
108 0 : cctx->cli_protocol_version = NULL;
109 :
110 0 : if (cli_protocol_version == NULL) {
111 0 : cli_protocol_version = register_cli_protocol_version();
112 : }
113 :
114 0 : if (cli_protocol_version != NULL) {
115 0 : cctx->cli_protocol_version = &cli_protocol_version[0];
116 :
117 0 : sss_packet_get_body(cctx->creq->in, &req_body, &req_blen);
118 0 : if (req_blen == sizeof(uint32_t)) {
119 0 : memcpy(&client_version, req_body, sizeof(uint32_t));
120 0 : DEBUG(SSSDBG_FUNC_DATA,
121 : "Received client version [%d].\n", client_version);
122 :
123 0 : i=0;
124 0 : while(cli_protocol_version[i].version>0) {
125 0 : if (cli_protocol_version[i].version == client_version) {
126 0 : cctx->cli_protocol_version = &cli_protocol_version[i];
127 0 : break;
128 : }
129 0 : i++;
130 : }
131 : }
132 : }
133 :
134 : /* create response packet */
135 0 : ret = sss_packet_new(cctx->creq, sizeof(uint32_t),
136 0 : sss_packet_get_cmd(cctx->creq->in),
137 0 : &cctx->creq->out);
138 0 : if (ret != EOK) {
139 0 : return ret;
140 : }
141 0 : sss_packet_get_body(cctx->creq->out, &body, &blen);
142 :
143 0 : protocol_version = (cctx->cli_protocol_version != NULL)
144 0 : ? cctx->cli_protocol_version->version : 0;
145 :
146 0 : SAFEALIGN_COPY_UINT32(body, &protocol_version, NULL);
147 0 : DEBUG(SSSDBG_FUNC_DATA, "Offered version [%d].\n", protocol_version);
148 :
149 0 : sss_cmd_done(cctx, NULL);
150 0 : return EOK;
151 : }
152 :
153 96 : int sss_cmd_execute(struct cli_ctx *cctx,
154 : enum sss_cli_command cmd,
155 : struct sss_cmd_table *sss_cmds)
156 : {
157 : int i;
158 :
159 851 : for (i = 0; sss_cmds[i].cmd != SSS_CLI_NULL; i++) {
160 851 : if (cmd == sss_cmds[i].cmd) {
161 96 : return sss_cmds[i].fn(cctx);
162 : }
163 : }
164 :
165 0 : return EINVAL;
166 : }
167 : struct setent_req_list {
168 : struct setent_req_list *prev;
169 : struct setent_req_list *next;
170 : /* Need to modify the list from a talloc destructor */
171 : struct setent_req_list **head;
172 :
173 : void *pvt;
174 :
175 : struct tevent_req *req;
176 : };
177 :
178 : struct tevent_req *
179 0 : setent_get_req(struct setent_req_list *sl)
180 : {
181 0 : return sl->req;
182 : }
183 :
184 0 : int setent_remove_ref(TALLOC_CTX *ctx)
185 : {
186 0 : struct setent_req_list *entry =
187 : talloc_get_type(ctx, struct setent_req_list);
188 0 : DLIST_REMOVE(*(entry->head), entry);
189 0 : return 0;
190 : }
191 :
192 0 : errno_t setent_add_ref(TALLOC_CTX *memctx,
193 : void *pvt,
194 : struct setent_req_list **list,
195 : struct tevent_req *req)
196 : {
197 : struct setent_req_list *entry;
198 :
199 0 : entry = talloc_zero(memctx, struct setent_req_list);
200 0 : if (!entry) {
201 0 : return ENOMEM;
202 : }
203 :
204 0 : entry->req = req;
205 0 : entry->pvt = pvt;
206 0 : DLIST_ADD_END(*list, entry, struct setent_req_list *);
207 0 : entry->head = list;
208 :
209 0 : talloc_set_destructor((TALLOC_CTX *)entry, setent_remove_ref);
210 0 : return EOK;
211 : }
212 :
213 0 : void setent_notify(struct setent_req_list **list, errno_t err)
214 : {
215 : struct setent_req_list *reql;
216 :
217 : /* Notify the waiting clients */
218 0 : while ((reql = *list) != NULL) {
219 : /* Each tevent_req_done() call will free
220 : * the request, removing it from the list.
221 : */
222 0 : if (err == EOK) {
223 0 : tevent_req_done(reql->req);
224 : } else {
225 0 : tevent_req_error(reql->req, err);
226 : }
227 :
228 0 : if (reql == *list) {
229 : /* The consumer failed to free the
230 : * request. Log a bug and continue.
231 : */
232 0 : DEBUG(SSSDBG_FATAL_FAILURE,
233 : "BUG: a callback did not free its request. "
234 : "May leak memory\n");
235 : /* Skip to the next since a memory leak is non-fatal */
236 0 : *list = (*list)->next;
237 : }
238 : }
239 0 : }
240 :
241 0 : void setent_notify_done(struct setent_req_list **list)
242 : {
243 0 : return setent_notify(list, EOK);
244 : }
245 :
246 : /*
247 : * Return values:
248 : * EOK - cache hit
249 : * EAGAIN - cache hit, but schedule off band update
250 : * ENOENT - cache miss
251 : */
252 : errno_t
253 59 : sss_cmd_check_cache(struct ldb_message *msg,
254 : int cache_refresh_percent,
255 : uint64_t cache_expire)
256 : {
257 : uint64_t lastUpdate;
258 59 : uint64_t midpoint_refresh = 0;
259 : time_t now;
260 :
261 59 : now = time(NULL);
262 59 : lastUpdate = ldb_msg_find_attr_as_uint64(msg, SYSDB_LAST_UPDATE, 0);
263 59 : midpoint_refresh = 0;
264 :
265 59 : if(cache_refresh_percent) {
266 14 : midpoint_refresh = lastUpdate +
267 7 : (cache_expire - lastUpdate)*cache_refresh_percent/100.0;
268 7 : if (midpoint_refresh - lastUpdate < 10) {
269 : /* If the percentage results in an expiration
270 : * less than ten seconds after the lastUpdate time,
271 : * that's too often we will simply set it to 10s
272 : */
273 0 : midpoint_refresh = lastUpdate+10;
274 : }
275 : }
276 :
277 59 : if (cache_expire > now) {
278 : /* cache still valid */
279 :
280 47 : if (midpoint_refresh && midpoint_refresh < now) {
281 : /* We're past the cache refresh timeout
282 : * We'll return the value from the cache, but we'll also
283 : * queue the cache entry for update out-of-band.
284 : */
285 7 : return EAGAIN;
286 : } else {
287 : /* Cache is still valid. */
288 40 : return EOK;
289 : }
290 : }
291 :
292 : /* Cache needs to be updated */
293 12 : return ENOENT;
294 : }
|