Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@redhat.com>
4 :
5 : Copyright (C) 2012 Red Hat
6 :
7 : Autofs responder: commands
8 :
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 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <talloc.h>
24 :
25 : #include "util/util.h"
26 : #include "responder/common/responder.h"
27 : #include "responder/common/responder_packet.h"
28 : #include "responder/autofs/autofs_private.h"
29 : #include "db/sysdb.h"
30 : #include "db/sysdb_autofs.h"
31 : #include "confdb/confdb.h"
32 :
33 0 : static int autofs_cmd_send_error(struct autofs_cmd_ctx *cmdctx, int err)
34 : {
35 0 : return sss_cmd_send_error(cmdctx->cctx, err);
36 : }
37 :
38 : static int
39 0 : autofs_cmd_send_empty(struct autofs_cmd_ctx *cmdctx)
40 : {
41 0 : return sss_cmd_send_empty(cmdctx->cctx, cmdctx);
42 : }
43 :
44 : static int
45 0 : autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
46 : {
47 0 : switch (ret) {
48 : case EOK:
49 : /* all fine, just return here */
50 0 : break;
51 :
52 : case ENOENT:
53 0 : ret = autofs_cmd_send_empty(cmdctx);
54 0 : if (ret) {
55 0 : return EFAULT;
56 : }
57 0 : break;
58 :
59 : case EAGAIN:
60 : /* async processing, just return here */
61 0 : break;
62 :
63 : case EFAULT:
64 : /* very bad error */
65 0 : return EFAULT;
66 :
67 : default:
68 0 : ret = autofs_cmd_send_error(cmdctx, ret);
69 0 : if (ret) {
70 0 : return EFAULT;
71 : }
72 0 : sss_cmd_done(cmdctx->cctx, cmdctx);
73 0 : break;
74 : }
75 :
76 0 : return EOK;
77 : }
78 :
79 : static errno_t
80 0 : autofs_setent_add_ref(TALLOC_CTX *memctx,
81 : struct autofs_map_ctx *map_ctx,
82 : struct tevent_req *req)
83 : {
84 0 : return setent_add_ref(memctx, map_ctx, &map_ctx->reqs, req);
85 : }
86 :
87 : static void
88 0 : autofs_setent_notify(struct autofs_map_ctx *map_ctx, errno_t ret)
89 : {
90 0 : setent_notify(&map_ctx->reqs, ret);
91 0 : }
92 :
93 : errno_t
94 0 : autofs_orphan_maps(struct autofs_ctx *actx)
95 : {
96 : int hret;
97 : unsigned long mcount;
98 : unsigned long i;
99 : hash_key_t *maps;
100 :
101 0 : if (!actx || !actx->maps) {
102 0 : return EINVAL;
103 : }
104 :
105 0 : hret = hash_keys(actx->maps, &mcount, &maps);
106 0 : if (hret != HASH_SUCCESS) {
107 0 : return EIO;
108 : }
109 :
110 0 : for (i = 0; i < mcount; i++) {
111 0 : hret = hash_delete(actx->maps, &maps[i]);
112 0 : if (hret != HASH_SUCCESS) {
113 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete key from hash\n");
114 0 : continue;
115 : }
116 : }
117 :
118 0 : return EOK;
119 : }
120 :
121 : static errno_t
122 0 : get_autofs_map(struct autofs_ctx *actx,
123 : char *mapname,
124 : struct autofs_map_ctx **map)
125 : {
126 : hash_key_t key;
127 : hash_value_t value;
128 : int hret;
129 :
130 0 : key.type = HASH_KEY_STRING;
131 0 : key.str = mapname;
132 :
133 0 : hret = hash_lookup(actx->maps, &key, &value);
134 0 : if (hret == HASH_SUCCESS) {
135 0 : *map = talloc_get_type(value.ptr, struct autofs_map_ctx);
136 0 : return EOK;
137 0 : } else if (hret == HASH_ERROR_KEY_NOT_FOUND) {
138 0 : return ENOENT;
139 : }
140 :
141 0 : DEBUG(SSSDBG_CRIT_FAILURE,
142 : "Unexpected error reading from autofs map hash [%d][%s]\n",
143 : hret, hash_error_string(hret));
144 0 : return EIO;
145 : }
146 :
147 : static int autofs_map_hash_remove (TALLOC_CTX *ctx);
148 :
149 : void
150 0 : autofs_map_hash_delete_cb(hash_entry_t *item,
151 : hash_destroy_enum deltype, void *pvt)
152 : {
153 : struct autofs_map_ctx *map;
154 :
155 0 : if (deltype != HASH_ENTRY_DESTROY) {
156 0 : return;
157 : }
158 :
159 0 : map = talloc_get_type(item->value.ptr, struct autofs_map_ctx);
160 0 : if (!map) {
161 0 : DEBUG(SSSDBG_OP_FAILURE, "Invalid autofs map\n");
162 0 : return;
163 : }
164 :
165 : /* So that the destructor wouldn't attempt to remove the map from hash
166 : * table */
167 0 : map->map_table = NULL;
168 : }
169 :
170 : static errno_t
171 0 : set_autofs_map(struct autofs_ctx *actx,
172 : struct autofs_map_ctx *map)
173 : {
174 : hash_key_t key;
175 : hash_value_t value;
176 : int hret;
177 :
178 0 : if (map->mapname == NULL) {
179 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs map name.\n");
180 0 : return EINVAL;
181 : }
182 :
183 : /* Add this entry to the hash table */
184 0 : key.type = HASH_KEY_STRING;
185 0 : key.str = map->mapname;
186 0 : value.type = HASH_VALUE_PTR;
187 0 : value.ptr = map;
188 0 : hret = hash_enter(actx->maps, &key, &value);
189 0 : if (hret != EOK) {
190 0 : DEBUG(SSSDBG_CRIT_FAILURE,
191 : "Unable to add hash table entry for [%s]\n", key.str);
192 0 : DEBUG(SSSDBG_MINOR_FAILURE,
193 : "Hash error [%d][%s]\n", hret, hash_error_string(hret));
194 0 : return EIO;
195 : }
196 0 : talloc_steal(actx->maps, map);
197 0 : talloc_set_destructor((TALLOC_CTX *) map, autofs_map_hash_remove);
198 :
199 0 : return EOK;
200 : }
201 :
202 : static int
203 0 : autofs_map_hash_remove(TALLOC_CTX *ctx)
204 : {
205 : int hret;
206 : hash_key_t key;
207 0 : struct autofs_map_ctx *map =
208 : talloc_get_type(ctx, struct autofs_map_ctx);
209 :
210 0 : if (map->map_table == NULL) {
211 0 : DEBUG(SSSDBG_TRACE_LIBS, "autofs map [%s] was already removed\n",
212 : map->mapname);
213 0 : return 0;
214 : }
215 :
216 0 : key.type = HASH_KEY_STRING;
217 0 : key.str = map->mapname;
218 :
219 : /* Remove the autofs map result object from the lookup table */
220 0 : hret = hash_delete(map->map_table, &key);
221 0 : if (hret != HASH_SUCCESS) {
222 0 : DEBUG(SSSDBG_CRIT_FAILURE,
223 : "Could not remove key from table! [%d][%s]\n",
224 : hret, hash_error_string(hret));
225 0 : return -1;
226 : }
227 0 : return 0;
228 : }
229 :
230 : static struct tevent_req *
231 : setautomntent_send(TALLOC_CTX *mem_ctx,
232 : const char *rawname,
233 : struct autofs_cmd_ctx *cmdctx);
234 : static errno_t setautomntent_recv(struct tevent_req *req);
235 : static void sss_autofs_cmd_setautomntent_done(struct tevent_req *req);
236 :
237 : /* FIXME - file a ticket to have per-responder private
238 : * data instead of growing the cli_ctx structure */
239 : static int
240 0 : sss_autofs_cmd_setautomntent(struct cli_ctx *client)
241 : {
242 : struct autofs_cmd_ctx *cmdctx;
243 : uint8_t *body;
244 : size_t blen;
245 0 : errno_t ret = EOK;
246 : const char *rawname;
247 : struct tevent_req *req;
248 :
249 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_setautomntent\n");
250 :
251 0 : cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
252 0 : if (!cmdctx) {
253 0 : return ENOMEM;
254 : }
255 0 : cmdctx->cctx = client;
256 :
257 0 : sss_packet_get_body(client->creq->in, &body, &blen);
258 :
259 : /* if not terminated fail */
260 0 : if (body[blen -1] != '\0') {
261 0 : ret = EINVAL;
262 0 : goto done;
263 : }
264 :
265 : /* If the body isn't valid UTF-8, fail */
266 0 : if (!sss_utf8_check(body, blen -1)) {
267 0 : ret = EINVAL;
268 0 : goto done;
269 : }
270 :
271 0 : rawname = (const char *)body;
272 0 : DEBUG(SSSDBG_TRACE_FUNC,
273 : "Got request for automount map named %s\n", rawname);
274 :
275 0 : req = setautomntent_send(cmdctx, rawname, cmdctx);
276 0 : if (!req) {
277 0 : DEBUG(SSSDBG_CRIT_FAILURE,
278 : "Fatal error calling setautomntent_send\n");
279 0 : ret = EIO;
280 0 : goto done;
281 : }
282 0 : tevent_req_set_callback(req, sss_autofs_cmd_setautomntent_done, cmdctx);
283 :
284 0 : ret = EOK;
285 : done:
286 0 : return autofs_cmd_done(cmdctx, ret);
287 : }
288 :
289 0 : static void sss_autofs_cmd_setautomntent_done(struct tevent_req *req)
290 : {
291 0 : struct autofs_cmd_ctx *cmdctx =
292 0 : tevent_req_callback_data(req, struct autofs_cmd_ctx);
293 : errno_t ret;
294 : errno_t reqret;
295 : struct sss_packet *packet;
296 : uint8_t *body;
297 : size_t blen;
298 :
299 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "setautomntent done\n");
300 :
301 0 : reqret = setautomntent_recv(req);
302 0 : talloc_zfree(req);
303 0 : if (reqret != EOK && reqret != ENOENT) {
304 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
305 0 : autofs_cmd_done(cmdctx, reqret);
306 0 : return;
307 : }
308 :
309 : /* Either we succeeded or no domains were eligible */
310 0 : ret = sss_packet_new(cmdctx->cctx->creq, 0,
311 0 : sss_packet_get_cmd(cmdctx->cctx->creq->in),
312 0 : &cmdctx->cctx->creq->out);
313 0 : if (ret == EOK) {
314 0 : if (reqret == ENOENT) {
315 0 : DEBUG(SSSDBG_TRACE_FUNC, "setautomntent did not find requested map\n");
316 : /* Notify the caller that this entry wasn't found */
317 0 : sss_cmd_empty_packet(cmdctx->cctx->creq->out);
318 : } else {
319 0 : DEBUG(SSSDBG_TRACE_FUNC, "setautomntent found data\n");
320 0 : packet = cmdctx->cctx->creq->out;
321 0 : ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
322 0 : if (ret != EOK) {
323 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't grow the packet\n");
324 0 : talloc_free(cmdctx);
325 0 : return;
326 : }
327 :
328 0 : sss_packet_get_body(packet, &body, &blen);
329 :
330 : /* Got some results */
331 0 : SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
332 :
333 : /* Reserved padding */
334 0 : SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
335 : }
336 :
337 0 : sss_cmd_done(cmdctx->cctx, NULL);
338 0 : return;
339 : }
340 :
341 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error creating packet\n");
342 0 : return;
343 : }
344 :
345 : struct setautomntent_state {
346 : struct autofs_cmd_ctx *cmdctx;
347 : struct autofs_dom_ctx *dctx;
348 :
349 : char *mapname;
350 : struct autofs_map_ctx *map;
351 : };
352 :
353 : struct setautomntent_lookup_ctx {
354 : struct autofs_ctx *actx;
355 : struct autofs_dom_ctx *dctx;
356 : struct resp_ctx *rctx;
357 : struct cli_ctx *cctx;
358 :
359 : bool returned_to_mainloop;
360 :
361 : char *mapname;
362 : struct autofs_map_ctx *map;
363 : };
364 :
365 : static errno_t
366 : lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx);
367 :
368 : static void
369 0 : autofs_map_result_timeout(struct tevent_context *ev,
370 : struct tevent_timer *te,
371 : struct timeval current_time,
372 : void *pvt)
373 : {
374 0 : struct autofs_map_ctx *map =
375 : talloc_get_type(pvt, struct autofs_map_ctx);
376 :
377 : /* Free the autofs map result context
378 : * The destructor for the autofs map will remove itself
379 : * from the hash table
380 : */
381 0 : talloc_free(map);
382 0 : }
383 :
384 : static void
385 0 : set_autofs_map_lifetime(uint32_t lifetime,
386 : struct setautomntent_lookup_ctx *lookup_ctx,
387 : struct autofs_map_ctx *map)
388 : {
389 : struct timeval tv;
390 : struct tevent_timer *te;
391 :
392 0 : tv = tevent_timeval_current_ofs(lifetime, 0);
393 0 : te = tevent_add_timer(lookup_ctx->rctx->ev,
394 : lookup_ctx->rctx, tv,
395 : autofs_map_result_timeout,
396 : map);
397 0 : if (!te) {
398 0 : DEBUG(SSSDBG_CRIT_FAILURE,
399 : "Could not set up life timer for autofs maps. "
400 : "Entries may become stale.\n");
401 : }
402 0 : }
403 :
404 : static errno_t
405 : setautomntent_get_autofs_map(struct autofs_ctx *actx,
406 : char *mapname,
407 : struct autofs_map_ctx **map);
408 :
409 : static struct tevent_req *
410 0 : setautomntent_send(TALLOC_CTX *mem_ctx,
411 : const char *rawname,
412 : struct autofs_cmd_ctx *cmdctx)
413 : {
414 : char *domname;
415 : errno_t ret;
416 : struct tevent_req *req;
417 : struct setautomntent_state *state;
418 0 : struct cli_ctx *client = cmdctx->cctx;
419 : struct autofs_dom_ctx *dctx;
420 0 : struct autofs_ctx *actx =
421 0 : talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
422 : struct setautomntent_lookup_ctx *lookup_ctx;
423 :
424 0 : req = tevent_req_create(mem_ctx, &state, struct setautomntent_state);
425 0 : if (!req) {
426 0 : DEBUG(SSSDBG_FATAL_FAILURE,
427 : "Could not create tevent request for setautomntent\n");
428 0 : return NULL;
429 : }
430 0 : state->cmdctx = cmdctx;
431 :
432 0 : dctx = talloc_zero(state, struct autofs_dom_ctx);
433 0 : if (!dctx) {
434 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory\n");
435 0 : ret = ENOMEM;
436 0 : goto fail;
437 : }
438 0 : dctx->cmd_ctx = state->cmdctx;
439 0 : state->dctx = dctx;
440 :
441 0 : ret = sss_parse_name_for_domains(state, client->rctx->domains,
442 : NULL, rawname,
443 0 : &domname, &state->mapname);
444 0 : if (ret != EOK) {
445 0 : DEBUG(SSSDBG_FATAL_FAILURE,
446 : "Invalid name received [%s]\n", rawname);
447 0 : goto fail;
448 : }
449 :
450 0 : DEBUG(SSSDBG_TRACE_FUNC,
451 : "Requesting info for automount map [%s] from [%s]\n",
452 : state->mapname, domname?domname:"<ALL>");
453 :
454 0 : if (domname) {
455 0 : dctx->domain = responder_get_domain(client->rctx, domname);
456 0 : if (!dctx->domain) {
457 0 : ret = EINVAL;
458 0 : goto fail;
459 : }
460 :
461 0 : client->automntmap_name = talloc_strdup(client, rawname);
462 0 : if (!client->automntmap_name) {
463 0 : ret = ENOMEM;
464 0 : goto fail;
465 : }
466 : } else {
467 : /* this is a multidomain search */
468 0 : dctx->domain = client->rctx->domains;
469 0 : cmdctx->check_next = true;
470 :
471 0 : client->automntmap_name = talloc_strdup(client, state->mapname);
472 0 : if (!client->automntmap_name) {
473 0 : ret = ENOMEM;
474 0 : goto fail;
475 : }
476 : }
477 :
478 0 : dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
479 : /* Is the result context already available?
480 : * Check for existing lookups for this map
481 : */
482 0 : ret = setautomntent_get_autofs_map(actx, state->mapname, &state->map);
483 0 : if (ret == EOK) {
484 : /* Another process already requested this map
485 : * Check whether it's ready for processing.
486 : */
487 0 : if (state->map->ready) {
488 0 : if (state->map->found) {
489 0 : DEBUG(SSSDBG_TRACE_LIBS,
490 : "Map %s is ready to be processed\n", state->mapname);
491 0 : tevent_req_done(req);
492 0 : tevent_req_post(req, actx->rctx->ev);
493 0 : return req;
494 : } else {
495 0 : DEBUG(SSSDBG_TRACE_LIBS,
496 : "Map %s was marked as nonexistent\n", state->mapname);
497 0 : tevent_req_error(req, ENOENT);
498 0 : tevent_req_post(req, actx->rctx->ev);
499 0 : return req;
500 : }
501 : }
502 :
503 : /* Result object is still being constructed
504 : * Register for notification when it's ready
505 : */
506 0 : DEBUG(SSSDBG_TRACE_LIBS,
507 : "Map %s is being looked up, registering for notification\n",
508 : state->mapname);
509 0 : ret = autofs_setent_add_ref(state, state->map, req);
510 0 : if (ret != EOK) {
511 0 : goto fail;
512 : }
513 : /* Will return control below */
514 0 : } else if (ret == ENOENT) {
515 0 : DEBUG(SSSDBG_TRACE_LIBS,
516 : "Map %s needs to be looked up\n", state->mapname);
517 :
518 0 : state->map = talloc_zero(actx, struct autofs_map_ctx);
519 0 : if (!state->map) {
520 0 : ret = ENOMEM;
521 0 : goto fail;
522 : }
523 0 : dctx->map_ctx = state->map;
524 :
525 0 : state->map->mapname = talloc_strdup(state->map, state->mapname);
526 0 : if (!state->map->mapname) {
527 0 : talloc_free(state->map);
528 0 : ret = ENOMEM;
529 0 : goto fail;
530 : }
531 0 : state->map->map_table = actx->maps;
532 :
533 0 : ret = autofs_setent_add_ref(state, state->map, req);
534 0 : if (ret != EOK) {
535 0 : talloc_free(state->map);
536 0 : goto fail;
537 : }
538 :
539 0 : ret = set_autofs_map(actx, state->map);
540 0 : if (ret != EOK) {
541 0 : talloc_free(state->map);
542 0 : goto fail;
543 : }
544 :
545 : /* Perform lookup */
546 0 : lookup_ctx = talloc_zero(state->map, struct setautomntent_lookup_ctx);
547 0 : if (!lookup_ctx) {
548 0 : talloc_free(state->map);
549 0 : ret = ENOMEM;
550 0 : goto fail;
551 : }
552 :
553 : /* Steal the dom_ctx onto the lookup_ctx so it doesn't go out of scope if
554 : * this request is canceled while other requests are in-progress.
555 : */
556 0 : lookup_ctx->dctx = talloc_steal(lookup_ctx, state->dctx);
557 0 : lookup_ctx->actx = actx;
558 0 : lookup_ctx->map = state->map;
559 0 : lookup_ctx->rctx = client->rctx;
560 0 : lookup_ctx->mapname =
561 0 : talloc_strdup(lookup_ctx, state->mapname);
562 0 : if (!lookup_ctx->mapname) {
563 0 : talloc_free(state->map);
564 0 : ret = ENOMEM;
565 0 : goto fail;
566 : }
567 :
568 0 : ret = lookup_automntmap_step(lookup_ctx);
569 0 : if (ret == EAGAIN) {
570 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "lookup_automntmap_step "
571 : "is refreshing the cache, re-entering the mainloop\n");
572 0 : return req;
573 0 : } else if (ret != EOK) {
574 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not get data from cache\n");
575 0 : talloc_free(state->map);
576 0 : ret = ENOMEM;
577 0 : goto fail;
578 : }
579 :
580 0 : tevent_req_done(req);
581 0 : tevent_req_post(req, cmdctx->cctx->ev);
582 0 : return req;
583 : } else {
584 0 : DEBUG(SSSDBG_CRIT_FAILURE,
585 : "Unexpected error from get_autofs_map [%d]: %s\n",
586 : ret, strerror(ret));
587 0 : goto fail;
588 : }
589 :
590 0 : return req;
591 :
592 : fail:
593 0 : tevent_req_error(req, ret);
594 0 : tevent_req_post(req, actx->rctx->ev);
595 0 : return req;
596 : }
597 :
598 : static errno_t
599 0 : setautomntent_get_autofs_map(struct autofs_ctx *actx,
600 : char *mapname,
601 : struct autofs_map_ctx **map)
602 : {
603 : errno_t ret;
604 :
605 0 : if (strcmp(mapname, "auto.master") == 0) {
606 : /* Iterate over the hash and remove all maps */
607 0 : ret = autofs_orphan_maps(actx);
608 0 : if (ret != EOK) {
609 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove existing maps from hash\n");
610 : }
611 0 : return ENOENT;
612 : }
613 :
614 0 : return get_autofs_map(actx, mapname, map);
615 : }
616 :
617 : static errno_t
618 : lookup_automntmap_update_cache(struct setautomntent_lookup_ctx *lookup_ctx);
619 :
620 : static errno_t
621 0 : lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx)
622 : {
623 : errno_t ret;
624 0 : struct sss_domain_info *dom = lookup_ctx->dctx->domain;
625 0 : struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
626 : struct sysdb_ctx *sysdb;
627 : struct autofs_map_ctx *map;
628 :
629 : /* Check each domain for this map name */
630 0 : while (dom) {
631 0 : if (dom != dctx->domain) {
632 : /* make sure we reset the check_provider flag when we check
633 : * a new domain */
634 0 : dctx->check_provider =
635 0 : NEED_CHECK_PROVIDER(dom->provider);
636 : }
637 :
638 : /* make sure to update the dctx if we changed domain */
639 0 : dctx->domain = dom;
640 :
641 0 : DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s@%s]\n",
642 : lookup_ctx->mapname, dom->name);
643 0 : sysdb = dom->sysdb;
644 0 : if (sysdb == NULL) {
645 0 : DEBUG(SSSDBG_FATAL_FAILURE,
646 : "Fatal: Sysdb CTX not found for this domain!\n");
647 0 : return EIO;
648 : }
649 :
650 : /* Look into the cache */
651 0 : talloc_free(dctx->map);
652 0 : ret = sysdb_get_map_byname(dctx, dom, lookup_ctx->mapname,
653 : &dctx->map);
654 0 : if (ret != EOK && ret != ENOENT) {
655 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not check cache\n");
656 0 : return ret;
657 0 : } else if (ret == ENOENT) {
658 0 : DEBUG(SSSDBG_MINOR_FAILURE,
659 : "No automount map [%s] in cache for domain [%s]\n",
660 : lookup_ctx->mapname, dom->name);
661 0 : if (!dctx->check_provider) {
662 0 : if (dctx->cmd_ctx->check_next) {
663 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Moving on to next domain\n");
664 0 : dom = get_next_domain(dom, false);
665 0 : continue;
666 : }
667 0 : else break;
668 : }
669 : }
670 :
671 0 : ret = get_autofs_map(lookup_ctx->actx, lookup_ctx->mapname, &map);
672 0 : if (ret != EOK) {
673 : /* Something really bad happened! */
674 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Autofs map entry was lost!\n");
675 0 : return ret;
676 : }
677 :
678 0 : if (dctx->map == NULL && !dctx->check_provider) {
679 0 : DEBUG(SSSDBG_MINOR_FAILURE,
680 : "Autofs map not found, setting negative cache\n");
681 0 : map->ready = true;
682 0 : map->found = false;
683 0 : set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
684 0 : return ENOENT;
685 : }
686 :
687 0 : if (dctx->check_provider) {
688 0 : ret = lookup_automntmap_update_cache(lookup_ctx);
689 0 : if (ret == EAGAIN) {
690 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
691 : "Looking up automount maps from the DP\n");
692 0 : return EAGAIN;
693 0 : } else if (ret != EOK) {
694 0 : DEBUG(SSSDBG_OP_FAILURE,
695 : "Error looking up automount maps [%d]: %s\n",
696 : ret, strerror(ret));
697 0 : return ret;
698 : }
699 : }
700 :
701 : /* OK, the map is in cache and valid.
702 : * Let's get all members and return it
703 : */
704 0 : ret = sysdb_autofs_entries_by_map(map, dom, map->mapname,
705 0 : &map->entry_count,
706 0 : &map->entries);
707 0 : if (ret != EOK && ret != ENOENT) {
708 0 : DEBUG(SSSDBG_OP_FAILURE,
709 : "Error looking automount map entries [%d]: %s\n",
710 : ret, strerror(ret));
711 0 : map->ready = true;
712 0 : map->found = false;
713 0 : set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
714 0 : return EIO;
715 : }
716 :
717 0 : map->map = talloc_steal(map, dctx->map);
718 :
719 0 : DEBUG(SSSDBG_TRACE_FUNC,
720 : "setautomntent done for map %s\n", lookup_ctx->mapname);
721 0 : map->ready = true;
722 0 : map->found = true;
723 0 : set_autofs_map_lifetime(dom->autofsmap_timeout, lookup_ctx, map);
724 0 : return EOK;
725 : }
726 :
727 0 : map = talloc_zero(lookup_ctx->actx, struct autofs_map_ctx);
728 0 : if (!map) {
729 0 : return ENOMEM;
730 : }
731 :
732 0 : map->ready = true;
733 0 : map->found = false;
734 0 : map->map_table = lookup_ctx->actx->maps;
735 :
736 0 : map->mapname = talloc_strdup(map, lookup_ctx->mapname);
737 0 : if (!map->mapname) {
738 0 : talloc_free(map);
739 0 : return ENOMEM;
740 : }
741 :
742 0 : ret = set_autofs_map(lookup_ctx->actx, map);
743 0 : if (ret != EOK) {
744 0 : talloc_free(map);
745 0 : return ENOMEM;
746 : }
747 :
748 0 : set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
749 :
750 : /* If we've gotten here, then no domain contained this map */
751 0 : return ENOENT;
752 : }
753 :
754 : static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
755 : const char *err_msg, void *ptr);
756 : static void autofs_dp_send_map_req_done(struct tevent_req *req);
757 :
758 : static errno_t
759 0 : lookup_automntmap_update_cache(struct setautomntent_lookup_ctx *lookup_ctx)
760 : {
761 : errno_t ret;
762 0 : uint64_t cache_expire = 0;
763 0 : struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
764 0 : struct tevent_req *req = NULL;
765 0 : struct dp_callback_ctx *cb_ctx = NULL;
766 :
767 0 : if (dctx->map != NULL) {
768 0 : if (strcmp(lookup_ctx->mapname, "auto.master") != 0) {
769 0 : cache_expire = ldb_msg_find_attr_as_uint64(dctx->map,
770 : SYSDB_CACHE_EXPIRE, 0);
771 : }
772 :
773 : /* if we have any reply let's check cache validity */
774 0 : ret = sss_cmd_check_cache(dctx->map, 0, cache_expire);
775 0 : if (ret == EOK) {
776 0 : DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning..\n");
777 0 : return EOK;
778 0 : } else if (ret != EAGAIN && ret != ENOENT) {
779 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache: %d\n", ret);
780 0 : goto error;
781 : }
782 : }
783 :
784 : /* dont loop forever :-) */
785 0 : dctx->check_provider = false;
786 :
787 : /* keep around current data in case backend is offline */
788 : /* FIXME - do this by default */
789 : #if 0
790 : if (dctx->res->count) {
791 : dctx->res = talloc_steal(dctx, dctx->res);
792 : }
793 : #endif
794 :
795 0 : req = sss_dp_get_autofs_send(lookup_ctx->cctx, lookup_ctx->rctx,
796 0 : lookup_ctx->dctx->domain, true,
797 0 : SSS_DP_AUTOFS, lookup_ctx->mapname);
798 0 : if (!req) {
799 0 : DEBUG(SSSDBG_CRIT_FAILURE,
800 : "Out of memory sending data provider request\n");
801 0 : ret = ENOMEM;
802 0 : goto error;
803 : }
804 :
805 0 : cb_ctx = talloc_zero(lookup_ctx->dctx, struct dp_callback_ctx);
806 0 : if(!cb_ctx) {
807 0 : talloc_zfree(req);
808 0 : ret = ENOMEM;
809 0 : goto error;
810 : }
811 0 : cb_ctx->callback = lookup_automntmap_cache_updated;
812 0 : cb_ctx->ptr = lookup_ctx;
813 0 : cb_ctx->cctx = lookup_ctx->dctx->cmd_ctx->cctx;
814 0 : cb_ctx->mem_ctx = lookup_ctx->dctx;
815 :
816 0 : tevent_req_set_callback(req, autofs_dp_send_map_req_done, cb_ctx);
817 :
818 0 : return EAGAIN;
819 :
820 : error:
821 0 : ret = autofs_cmd_send_error(lookup_ctx->dctx->cmd_ctx, ret);
822 0 : if (ret != EOK) {
823 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
824 0 : talloc_free(lookup_ctx->cctx);
825 0 : return ret;
826 : }
827 0 : autofs_cmd_done(lookup_ctx->dctx->cmd_ctx, ret);
828 0 : return EOK;
829 : }
830 :
831 0 : static void autofs_dp_send_map_req_done(struct tevent_req *req)
832 : {
833 0 : struct dp_callback_ctx *cb_ctx =
834 0 : tevent_req_callback_data(req, struct dp_callback_ctx);
835 0 : struct setautomntent_lookup_ctx *lookup_ctx =
836 0 : talloc_get_type(cb_ctx->ptr, struct setautomntent_lookup_ctx);
837 :
838 : errno_t ret;
839 : dbus_uint16_t err_maj;
840 : dbus_uint32_t err_min;
841 : char *err_msg;
842 :
843 0 : ret = sss_dp_get_autofs_recv(cb_ctx->mem_ctx, req,
844 : &err_maj, &err_min,
845 : &err_msg);
846 0 : talloc_free(req);
847 0 : if (ret != EOK) {
848 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
849 0 : talloc_free(lookup_ctx->cctx);
850 0 : return;
851 : }
852 :
853 0 : cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
854 : }
855 :
856 0 : static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
857 : const char *err_msg, void *ptr)
858 : {
859 0 : struct setautomntent_lookup_ctx *lookup_ctx =
860 : talloc_get_type(ptr, struct setautomntent_lookup_ctx);
861 0 : struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
862 : errno_t ret;
863 :
864 0 : if (err_maj) {
865 0 : DEBUG(SSSDBG_CRIT_FAILURE,
866 : "Unable to get information from Data Provider\n"
867 : "Error: %u, %u, %s\n"
868 : "Will try to return what we have in cache\n",
869 : (unsigned int)err_maj, (unsigned int)err_min, err_msg);
870 : /* Loop to the next domain if possible */
871 0 : if (dctx->cmd_ctx->check_next && get_next_domain(dctx->domain, false)) {
872 0 : dctx->domain = get_next_domain(dctx->domain, false);
873 0 : dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
874 : }
875 : }
876 :
877 : /* ok the backend returned, search to see if we have updated results */
878 0 : ret = lookup_automntmap_step(lookup_ctx);
879 0 : if (ret != EOK) {
880 0 : if (ret == EAGAIN) {
881 0 : return;
882 : }
883 : }
884 :
885 : /* We have results to return */
886 0 : autofs_setent_notify(lookup_ctx->map, ret);
887 : }
888 :
889 : static errno_t
890 0 : setautomntent_recv(struct tevent_req *req)
891 : {
892 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
893 0 : return EOK;
894 : }
895 :
896 : static errno_t
897 : getautomntent_process(struct autofs_cmd_ctx *cmdctx,
898 : struct autofs_map_ctx *map,
899 : uint32_t cursor, uint32_t max_entries);
900 : static void
901 : getautomntent_implicit_done(struct tevent_req *req);
902 : static errno_t
903 : fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp);
904 :
905 :
906 : static int
907 0 : sss_autofs_cmd_getautomntent(struct cli_ctx *client)
908 : {
909 : struct autofs_cmd_ctx *cmdctx;
910 : struct autofs_map_ctx *map;
911 : struct autofs_ctx *actx;
912 : uint8_t *body;
913 : size_t blen;
914 : errno_t ret;
915 : uint32_t namelen;
916 0 : size_t c = 0;
917 : struct tevent_req *req;
918 :
919 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntent\n");
920 :
921 0 : cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
922 0 : if (!cmdctx) {
923 0 : return ENOMEM;
924 : }
925 0 : cmdctx->cctx = client;
926 :
927 0 : actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
928 0 : if (!actx) {
929 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs context\n");
930 0 : return EIO;
931 : }
932 :
933 : /* get autofs map name and index to query */
934 0 : sss_packet_get_body(client->creq->in, &body, &blen);
935 :
936 0 : SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
937 :
938 0 : if (namelen == 0 || namelen > blen - c) {
939 0 : ret = EINVAL;
940 0 : goto done;
941 : }
942 :
943 0 : cmdctx->mapname = (char *) body+c;
944 :
945 : /* if not null-terminated fail */
946 0 : if (cmdctx->mapname[namelen] != '\0') {
947 0 : ret = EINVAL;
948 0 : goto done;
949 : }
950 :
951 : /* If the name isn't valid UTF-8, fail */
952 0 : if (!sss_utf8_check((const uint8_t *) cmdctx->mapname, namelen -1)) {
953 0 : ret = EINVAL;
954 0 : goto done;
955 : }
956 :
957 0 : SAFEALIGN_COPY_UINT32_CHECK(&cmdctx->cursor, body+c+namelen+1, blen, &c);
958 0 : SAFEALIGN_COPY_UINT32_CHECK(&cmdctx->max_entries, body+c+namelen+1, blen, &c);
959 :
960 0 : DEBUG(SSSDBG_TRACE_FUNC,
961 : "Requested data of map %s cursor %d max entries %d\n",
962 : cmdctx->mapname, cmdctx->cursor, cmdctx->max_entries);
963 :
964 0 : ret = get_autofs_map(actx, cmdctx->mapname, &map);
965 0 : if (ret == ENOENT) {
966 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
967 0 : req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
968 0 : if (req == NULL) {
969 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
970 0 : ret = EIO;
971 0 : goto done;
972 : }
973 :
974 0 : tevent_req_set_callback(req, getautomntent_implicit_done, cmdctx);
975 0 : ret = EOK;
976 0 : goto done;
977 0 : } else if (ret != EOK) {
978 0 : DEBUG(SSSDBG_OP_FAILURE,
979 : "An unexpected error occurred: [%d][%s]\n",
980 : ret, strerror(ret));
981 0 : goto done;
982 : }
983 :
984 0 : if (map->ready == false) {
985 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
986 0 : req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
987 0 : if (req == NULL) {
988 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
989 0 : ret = EIO;
990 0 : goto done;
991 : }
992 :
993 0 : tevent_req_set_callback(req, getautomntent_implicit_done, cmdctx);
994 0 : ret = EOK;
995 0 : goto done;
996 0 : } else if (map->found == false) {
997 0 : DEBUG(SSSDBG_TRACE_FUNC, "negative cache hit\n");
998 0 : ret = ENOENT;
999 0 : goto done;
1000 : }
1001 :
1002 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1003 : "returning entries for [%s]\n", map->mapname);
1004 :
1005 0 : ret = getautomntent_process(cmdctx, map, cmdctx->cursor, cmdctx->max_entries);
1006 :
1007 : done:
1008 0 : return autofs_cmd_done(cmdctx, ret);
1009 : }
1010 :
1011 : static void
1012 0 : getautomntent_implicit_done(struct tevent_req *req)
1013 : {
1014 : errno_t ret;
1015 : struct autofs_map_ctx *map;
1016 0 : struct autofs_cmd_ctx *cmdctx =
1017 0 : tevent_req_callback_data(req, struct autofs_cmd_ctx);
1018 0 : struct autofs_ctx *actx =
1019 0 : talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct autofs_ctx);
1020 :
1021 0 : ret = setautomntent_recv(req);
1022 0 : talloc_zfree(req);
1023 0 : if (ret != EOK) {
1024 0 : if (ret != ENOENT) {
1025 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
1026 : } else {
1027 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No such map\n");
1028 : }
1029 0 : goto done;
1030 : }
1031 :
1032 0 : ret = get_autofs_map(actx, cmdctx->mapname, &map);
1033 0 : if (ret != EOK) {
1034 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1035 : "Cannot get map after setautomntent succeeded?\n");
1036 0 : goto done;
1037 : }
1038 :
1039 0 : if (map->ready == false) {
1040 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1041 : "Map not ready after setautomntent succeeded\n");
1042 0 : goto done;
1043 : }
1044 :
1045 0 : ret = getautomntent_process(cmdctx, map,
1046 : cmdctx->cursor, cmdctx->max_entries);
1047 : done:
1048 0 : autofs_cmd_done(cmdctx, ret);
1049 0 : return;
1050 : }
1051 :
1052 : static errno_t
1053 0 : getautomntent_process(struct autofs_cmd_ctx *cmdctx,
1054 : struct autofs_map_ctx *map,
1055 : uint32_t cursor, uint32_t max_entries)
1056 : {
1057 0 : struct cli_ctx *client = cmdctx->cctx;
1058 : errno_t ret;
1059 : struct ldb_message *entry;
1060 : size_t rp;
1061 : uint32_t i, stop, left, nentries;
1062 : uint8_t *body;
1063 : size_t blen;
1064 :
1065 : /* create response packet */
1066 0 : ret = sss_packet_new(client->creq, 0,
1067 0 : sss_packet_get_cmd(client->creq->in),
1068 0 : &client->creq->out);
1069 0 : if (ret != EOK) {
1070 0 : return ret;
1071 : }
1072 :
1073 0 : if (!map->map || !map->entries || !map->entries[0] ||
1074 0 : cursor >= map->entry_count) {
1075 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No entries found\n");
1076 0 : ret = sss_cmd_empty_packet(client->creq->out);
1077 0 : if (ret != EOK) {
1078 0 : return autofs_cmd_done(cmdctx, ret);
1079 : }
1080 0 : goto done;
1081 : }
1082 :
1083 : /* allocate memory for number of entries in the packet */
1084 0 : ret = sss_packet_grow(client->creq->out, sizeof(uint32_t));
1085 0 : if (ret != EOK) {
1086 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
1087 0 : goto done;
1088 : }
1089 :
1090 0 : rp = sizeof(uint32_t); /* We'll write the number of entries here */
1091 :
1092 0 : left = map->entry_count - cursor;
1093 0 : stop = max_entries < left ? max_entries : left;
1094 :
1095 0 : nentries = 0;
1096 0 : for (i=0; i < stop; i++) {
1097 0 : entry = map->entries[cursor];
1098 0 : cursor++;
1099 :
1100 0 : ret = fill_autofs_entry(entry, client->creq->out, &rp);
1101 0 : if (ret != EOK) {
1102 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1103 : "Cannot fill entry %d/%d, skipping\n", i, stop);
1104 0 : continue;
1105 : }
1106 0 : nentries++;
1107 : }
1108 :
1109 : /* packet grows in fill_autofs_entry, body pointer may change,
1110 : * thus we have to obtain it here */
1111 0 : sss_packet_get_body(client->creq->out, &body, &blen);
1112 :
1113 0 : rp = 0;
1114 0 : SAFEALIGN_SET_UINT32(&body[rp], nentries, &rp);
1115 :
1116 0 : ret = EOK;
1117 : done:
1118 0 : sss_packet_set_error(client->creq->out, ret);
1119 0 : sss_cmd_done(client, cmdctx);
1120 :
1121 0 : return EOK;
1122 : }
1123 :
1124 : static errno_t
1125 0 : fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp)
1126 : {
1127 : errno_t ret;
1128 : const char *key;
1129 : size_t keylen;
1130 : const char *value;
1131 : size_t valuelen;
1132 : uint8_t *body;
1133 : size_t blen;
1134 : size_t len;
1135 :
1136 0 : key = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_KEY, NULL);
1137 0 : value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
1138 0 : if (!key || !value) {
1139 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Incomplete entry\n");
1140 0 : return EINVAL;
1141 : }
1142 :
1143 0 : keylen = 1 + strlen(key);
1144 0 : valuelen = 1 + strlen(value);
1145 0 : len = sizeof(uint32_t) + sizeof(uint32_t) + keylen + sizeof(uint32_t) + valuelen;
1146 :
1147 0 : ret = sss_packet_grow(packet, len);
1148 0 : if (ret != EOK) {
1149 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
1150 0 : return ret;
1151 : }
1152 :
1153 0 : sss_packet_get_body(packet, &body, &blen);
1154 :
1155 0 : SAFEALIGN_SET_UINT32(&body[*rp], len, rp);
1156 0 : SAFEALIGN_SET_UINT32(&body[*rp], keylen, rp);
1157 :
1158 0 : if (keylen == 1) {
1159 0 : body[*rp] = '\0';
1160 : } else {
1161 0 : memcpy(&body[*rp], key, keylen);
1162 : }
1163 0 : *rp += keylen;
1164 :
1165 0 : SAFEALIGN_SET_UINT32(&body[*rp], valuelen, rp);
1166 0 : if (valuelen == 1) {
1167 0 : body[*rp] = '\0';
1168 : } else {
1169 0 : memcpy(&body[*rp], value, valuelen);
1170 : }
1171 0 : *rp += valuelen;
1172 :
1173 0 : return EOK;
1174 : }
1175 :
1176 : static errno_t
1177 : getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
1178 : struct autofs_map_ctx *map,
1179 : const char *key);
1180 : static void
1181 : getautomntbyname_implicit_done(struct tevent_req *req);
1182 :
1183 : static int
1184 0 : sss_autofs_cmd_getautomntbyname(struct cli_ctx *client)
1185 : {
1186 : errno_t ret;
1187 : struct autofs_cmd_ctx *cmdctx;
1188 : struct autofs_map_ctx *map;
1189 : struct autofs_ctx *actx;
1190 : uint8_t *body;
1191 : size_t blen;
1192 : uint32_t namelen;
1193 : uint32_t keylen;
1194 0 : size_t c = 0;
1195 : struct tevent_req *req;
1196 :
1197 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntbyname\n");
1198 :
1199 0 : cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
1200 0 : if (!cmdctx) {
1201 0 : return ENOMEM;
1202 : }
1203 0 : cmdctx->cctx = client;
1204 :
1205 0 : actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
1206 0 : if (!actx) {
1207 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs context\n");
1208 0 : return EIO;
1209 : }
1210 :
1211 : /* get autofs map name and index to query */
1212 0 : sss_packet_get_body(client->creq->in, &body, &blen);
1213 :
1214 : /* FIXME - split out a function to get string from <len><str>\0 */
1215 0 : SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
1216 :
1217 0 : if (namelen == 0 || namelen > blen - c) {
1218 0 : ret = EINVAL;
1219 0 : goto done;
1220 : }
1221 :
1222 0 : cmdctx->mapname = (char *) body+c;
1223 :
1224 : /* if not null-terminated fail */
1225 0 : if (cmdctx->mapname[namelen] != '\0') {
1226 0 : ret = EINVAL;
1227 0 : goto done;
1228 : }
1229 :
1230 : /* If the name isn't valid UTF-8, fail */
1231 0 : if (!sss_utf8_check((const uint8_t *) cmdctx->mapname, namelen -1)) {
1232 0 : ret = EINVAL;
1233 0 : goto done;
1234 : }
1235 :
1236 0 : c += namelen + 1;
1237 :
1238 : /* FIXME - split out a function to get string from <len><str>\0 */
1239 0 : SAFEALIGN_COPY_UINT32_CHECK(&keylen, body+c, blen, &c);
1240 :
1241 0 : if (keylen == 0 || keylen > blen - c) {
1242 0 : ret = EINVAL;
1243 0 : goto done;
1244 : }
1245 :
1246 0 : cmdctx->key = (char *) body+c;
1247 :
1248 : /* if not null-terminated fail */
1249 0 : if (cmdctx->key[keylen] != '\0') {
1250 0 : ret = EINVAL;
1251 0 : goto done;
1252 : }
1253 :
1254 : /* If the key isn't valid UTF-8, fail */
1255 0 : if (!sss_utf8_check((const uint8_t *) cmdctx->key, keylen -1)) {
1256 0 : ret = EINVAL;
1257 0 : goto done;
1258 : }
1259 :
1260 0 : DEBUG(SSSDBG_TRACE_FUNC,
1261 : "Requested data of map %s key %s\n", cmdctx->mapname, cmdctx->key);
1262 :
1263 0 : ret = get_autofs_map(actx, cmdctx->mapname, &map);
1264 0 : if (ret == ENOENT) {
1265 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
1266 0 : req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
1267 0 : if (req == NULL) {
1268 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
1269 0 : ret = EIO;
1270 0 : goto done;
1271 : }
1272 :
1273 0 : tevent_req_set_callback(req, getautomntbyname_implicit_done, cmdctx);
1274 0 : ret = EOK;
1275 0 : goto done;
1276 0 : } else if (ret != EOK) {
1277 0 : DEBUG(SSSDBG_OP_FAILURE,
1278 : "An unexpected error occurred: [%d][%s]\n",
1279 : ret, strerror(ret));
1280 0 : goto done;
1281 : }
1282 :
1283 0 : if (map->ready == false) {
1284 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
1285 0 : req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
1286 0 : if (req == NULL) {
1287 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
1288 0 : ret = EIO;
1289 0 : goto done;
1290 : }
1291 :
1292 0 : tevent_req_set_callback(req, getautomntbyname_implicit_done, cmdctx);
1293 0 : ret = EOK;
1294 0 : goto done;
1295 0 : } else if (map->found == false) {
1296 0 : DEBUG(SSSDBG_TRACE_FUNC, "negative cache hit\n");
1297 0 : ret = ENOENT;
1298 0 : goto done;
1299 : }
1300 :
1301 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1302 : "Looking up value for [%s] in [%s]\n", cmdctx->key, map->mapname);
1303 :
1304 0 : ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
1305 :
1306 : done:
1307 0 : return autofs_cmd_done(cmdctx, ret);
1308 : }
1309 :
1310 : static void
1311 0 : getautomntbyname_implicit_done(struct tevent_req *req)
1312 : {
1313 : errno_t ret;
1314 : struct autofs_map_ctx *map;
1315 0 : struct autofs_cmd_ctx *cmdctx =
1316 0 : tevent_req_callback_data(req, struct autofs_cmd_ctx);
1317 0 : struct autofs_ctx *actx =
1318 0 : talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct autofs_ctx);
1319 :
1320 0 : ret = setautomntent_recv(req);
1321 0 : talloc_zfree(req);
1322 0 : if (ret != EOK) {
1323 0 : if (ret != ENOENT) {
1324 0 : DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
1325 : } else {
1326 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No such map\n");
1327 : }
1328 0 : goto done;
1329 : }
1330 :
1331 0 : ret = get_autofs_map(actx, cmdctx->mapname, &map);
1332 0 : if (ret != EOK) {
1333 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1334 : "Cannot get map after setautomntent succeeded?\n");
1335 0 : goto done;
1336 : }
1337 :
1338 0 : if (map->ready == false) {
1339 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1340 : "Map not ready after setautomntent succeeded\n");
1341 0 : goto done;
1342 : }
1343 :
1344 0 : ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
1345 : done:
1346 0 : autofs_cmd_done(cmdctx, ret);
1347 0 : return;
1348 : }
1349 :
1350 : static errno_t
1351 0 : getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
1352 : struct autofs_map_ctx *map,
1353 : const char *key)
1354 : {
1355 0 : struct cli_ctx *client = cmdctx->cctx;
1356 : errno_t ret;
1357 : size_t i;
1358 : const char *k;
1359 : const char *value;
1360 : size_t valuelen;
1361 : size_t len;
1362 : uint8_t *body;
1363 : size_t blen, rp;
1364 :
1365 : /* create response packet */
1366 0 : ret = sss_packet_new(client->creq, 0,
1367 0 : sss_packet_get_cmd(client->creq->in),
1368 0 : &client->creq->out);
1369 0 : if (ret != EOK) {
1370 0 : return ret;
1371 : }
1372 :
1373 0 : if (!map->map || !map->entries || !map->entries[0]) {
1374 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No entries found\n");
1375 0 : ret = sss_cmd_empty_packet(client->creq->out);
1376 0 : if (ret != EOK) {
1377 0 : return autofs_cmd_done(cmdctx, ret);
1378 : }
1379 0 : goto done;
1380 : }
1381 :
1382 0 : for (i=0; i < map->entry_count; i++) {
1383 0 : k = ldb_msg_find_attr_as_string(map->entries[i],
1384 : SYSDB_AUTOFS_ENTRY_KEY, NULL);
1385 0 : if (!k) {
1386 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Skipping incomplete entry\n");
1387 0 : continue;
1388 : }
1389 :
1390 0 : if (strcmp(k, key) == 0) {
1391 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", key);
1392 0 : break;
1393 : }
1394 : }
1395 :
1396 0 : if (i >= map->entry_count) {
1397 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No key named [%s] found\n", key);
1398 0 : ret = sss_cmd_empty_packet(client->creq->out);
1399 0 : if (ret != EOK) {
1400 0 : return autofs_cmd_done(cmdctx, ret);
1401 : }
1402 0 : goto done;
1403 : }
1404 :
1405 0 : value = ldb_msg_find_attr_as_string(map->entries[i],
1406 : SYSDB_AUTOFS_ENTRY_VALUE, NULL);
1407 :
1408 0 : valuelen = 1 + strlen(value);
1409 0 : len = sizeof(uint32_t) + sizeof(uint32_t) + valuelen;
1410 :
1411 0 : ret = sss_packet_grow(client->creq->out, len);
1412 0 : if (ret != EOK) {
1413 0 : goto done;
1414 : }
1415 :
1416 0 : sss_packet_get_body(client->creq->out, &body, &blen);
1417 :
1418 0 : rp = 0;
1419 0 : SAFEALIGN_SET_UINT32(&body[rp], len, &rp);
1420 :
1421 0 : SAFEALIGN_SET_UINT32(&body[rp], valuelen, &rp);
1422 0 : if (valuelen == 1) {
1423 0 : body[rp] = '\0';
1424 : } else {
1425 0 : memcpy(&body[rp], value, valuelen);
1426 : }
1427 0 : rp += valuelen;
1428 :
1429 0 : ret = EOK;
1430 : done:
1431 0 : sss_packet_set_error(client->creq->out, ret);
1432 0 : sss_cmd_done(client, cmdctx);
1433 :
1434 0 : return EOK;
1435 : }
1436 :
1437 : static int
1438 0 : sss_autofs_cmd_endautomntent(struct cli_ctx *client)
1439 : {
1440 : errno_t ret;
1441 :
1442 0 : DEBUG(SSSDBG_TRACE_FUNC, "endautomntent called\n");
1443 :
1444 : /* create response packet */
1445 0 : ret = sss_packet_new(client->creq, 0,
1446 0 : sss_packet_get_cmd(client->creq->in),
1447 0 : &client->creq->out);
1448 :
1449 0 : if (ret != EOK) {
1450 0 : return ret;
1451 : }
1452 :
1453 0 : sss_cmd_done(client, NULL);
1454 0 : return EOK;
1455 : }
1456 :
1457 0 : struct cli_protocol_version *register_cli_protocol_version(void)
1458 : {
1459 : static struct cli_protocol_version autofs_cli_protocol_version[] = {
1460 : { SSS_AUTOFS_PROTO_VERSION, NULL, NULL }
1461 : };
1462 :
1463 0 : return autofs_cli_protocol_version;
1464 : }
1465 :
1466 0 : struct sss_cmd_table *get_autofs_cmds(void)
1467 : {
1468 : static struct sss_cmd_table autofs_cmds[] = {
1469 : { SSS_GET_VERSION, sss_cmd_get_version },
1470 : { SSS_AUTOFS_SETAUTOMNTENT, sss_autofs_cmd_setautomntent },
1471 : { SSS_AUTOFS_GETAUTOMNTENT, sss_autofs_cmd_getautomntent },
1472 : { SSS_AUTOFS_GETAUTOMNTBYNAME, sss_autofs_cmd_getautomntbyname },
1473 : { SSS_AUTOFS_ENDAUTOMNTENT, sss_autofs_cmd_endautomntent },
1474 : { SSS_CLI_NULL, NULL}
1475 : };
1476 :
1477 0 : return autofs_cmds;
1478 : }
|