Use CRITICAL job priority class for long running dispatcher jobs
[strongswan.git] / src / libcharon / plugins / stroke / stroke_socket.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "stroke_socket.h"
17
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include <hydra.h>
28 #include <daemon.h>
29 #include <threading/thread.h>
30 #include <processing/jobs/callback_job.h>
31
32 #include "stroke_config.h"
33 #include "stroke_control.h"
34 #include "stroke_cred.h"
35 #include "stroke_ca.h"
36 #include "stroke_attribute.h"
37 #include "stroke_list.h"
38
39 typedef struct stroke_job_context_t stroke_job_context_t;
40 typedef struct private_stroke_socket_t private_stroke_socket_t;
41
42 /**
43 * private data of stroke_socket
44 */
45 struct private_stroke_socket_t {
46
47 /**
48 * public functions
49 */
50 stroke_socket_t public;
51
52 /**
53 * Unix socket to listen for strokes
54 */
55 int socket;
56
57 /**
58 * job accepting stroke messages
59 */
60 callback_job_t *job;
61
62 /**
63 * configuration backend
64 */
65 stroke_config_t *config;
66
67 /**
68 * attribute provider
69 */
70 stroke_attribute_t *attribute;
71
72 /**
73 * controller to control daemon
74 */
75 stroke_control_t *control;
76
77 /**
78 * credential set
79 */
80 stroke_cred_t *cred;
81
82 /**
83 * CA sections
84 */
85 stroke_ca_t *ca;
86
87 /**
88 * Status information logging
89 */
90 stroke_list_t *list;
91 };
92
93 /**
94 * job context to pass to processing thread
95 */
96 struct stroke_job_context_t {
97
98 /**
99 * file descriptor to read from
100 */
101 int fd;
102
103 /**
104 * global stroke interface
105 */
106 private_stroke_socket_t *this;
107 };
108
109 /**
110 * Helper function which corrects the string pointers
111 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
112 * contains RELATIVE addresses (relative to the beginning of the
113 * stroke_msg). They must be corrected if they reach our address
114 * space...
115 */
116 static void pop_string(stroke_msg_t *msg, char **string)
117 {
118 if (*string == NULL)
119 {
120 return;
121 }
122
123 /* check for sanity of string pointer and string */
124 if (string < (char**)msg ||
125 string > (char**)((char*)msg + sizeof(stroke_msg_t)) ||
126 (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) ||
127 (unsigned long)*string > msg->length)
128 {
129 *string = "(invalid pointer in stroke msg)";
130 }
131 else
132 {
133 *string = (char*)msg + (unsigned long)*string;
134 }
135 }
136
137 /**
138 * Pop the strings of a stroke_end_t struct and log them for debugging purposes
139 */
140 static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
141 {
142 pop_string(msg, &end->address);
143 pop_string(msg, &end->subnets);
144 pop_string(msg, &end->sourceip);
145 pop_string(msg, &end->auth);
146 pop_string(msg, &end->auth2);
147 pop_string(msg, &end->id);
148 pop_string(msg, &end->id2);
149 pop_string(msg, &end->cert);
150 pop_string(msg, &end->cert2);
151 pop_string(msg, &end->ca);
152 pop_string(msg, &end->ca2);
153 pop_string(msg, &end->groups);
154 pop_string(msg, &end->cert_policy);
155 pop_string(msg, &end->updown);
156
157 DBG2(DBG_CFG, " %s=%s", label, end->address);
158 DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets);
159 DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip);
160 DBG2(DBG_CFG, " %sauth=%s", label, end->auth);
161 DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2);
162 DBG2(DBG_CFG, " %sid=%s", label, end->id);
163 DBG2(DBG_CFG, " %sid2=%s", label, end->id2);
164 DBG2(DBG_CFG, " %scert=%s", label, end->cert);
165 DBG2(DBG_CFG, " %scert2=%s", label, end->cert2);
166 DBG2(DBG_CFG, " %sca=%s", label, end->ca);
167 DBG2(DBG_CFG, " %sca2=%s", label, end->ca2);
168 DBG2(DBG_CFG, " %sgroups=%s", label, end->groups);
169 DBG2(DBG_CFG, " %supdown=%s", label, end->updown);
170 }
171
172 /**
173 * Add a connection to the configuration list
174 */
175 static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
176 {
177 pop_string(msg, &msg->add_conn.name);
178 DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
179
180 DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
181 pop_end(msg, "left", &msg->add_conn.me);
182 pop_end(msg, "right", &msg->add_conn.other);
183 pop_string(msg, &msg->add_conn.eap_identity);
184 pop_string(msg, &msg->add_conn.aaa_identity);
185 pop_string(msg, &msg->add_conn.algorithms.ike);
186 pop_string(msg, &msg->add_conn.algorithms.esp);
187 pop_string(msg, &msg->add_conn.ikeme.mediated_by);
188 pop_string(msg, &msg->add_conn.ikeme.peerid);
189 DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity);
190 DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity);
191 DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
192 DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
193 DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
194 DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by);
195 DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid);
196
197 this->config->add(this->config, msg);
198 this->attribute->add_pool(this->attribute, msg);
199 }
200
201 /**
202 * Delete a connection from the list
203 */
204 static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
205 {
206 pop_string(msg, &msg->del_conn.name);
207 DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
208
209 this->config->del(this->config, msg);
210 this->attribute->del_pool(this->attribute, msg);
211 }
212
213 /**
214 * initiate a connection by name
215 */
216 static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
217 {
218 pop_string(msg, &msg->initiate.name);
219 DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
220
221 this->control->initiate(this->control, msg, out);
222 }
223
224 /**
225 * terminate a connection by name
226 */
227 static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
228 {
229 pop_string(msg, &msg->terminate.name);
230 DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
231
232 this->control->terminate(this->control, msg, out);
233 }
234
235 /**
236 * terminate a connection by peers virtual IP
237 */
238 static void stroke_terminate_srcip(private_stroke_socket_t *this,
239 stroke_msg_t *msg, FILE *out)
240 {
241 pop_string(msg, &msg->terminate_srcip.start);
242 pop_string(msg, &msg->terminate_srcip.end);
243 DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s",
244 msg->terminate_srcip.start, msg->terminate_srcip.end);
245
246 this->control->terminate_srcip(this->control, msg, out);
247 }
248
249 /**
250 * rekey a connection by name/id
251 */
252 static void stroke_rekey(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
253 {
254 pop_string(msg, &msg->terminate.name);
255 DBG1(DBG_CFG, "received stroke: rekey '%s'", msg->rekey.name);
256
257 this->control->rekey(this->control, msg, out);
258 }
259
260 /**
261 * route a policy (install SPD entries)
262 */
263 static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
264 {
265 pop_string(msg, &msg->route.name);
266 DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name);
267
268 this->control->route(this->control, msg, out);
269 }
270
271 /**
272 * unroute a policy
273 */
274 static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
275 {
276 pop_string(msg, &msg->terminate.name);
277 DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name);
278
279 this->control->unroute(this->control, msg, out);
280 }
281
282 /**
283 * Add a ca information record to the cainfo list
284 */
285 static void stroke_add_ca(private_stroke_socket_t *this,
286 stroke_msg_t *msg, FILE *out)
287 {
288 pop_string(msg, &msg->add_ca.name);
289 DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
290
291 pop_string(msg, &msg->add_ca.cacert);
292 pop_string(msg, &msg->add_ca.crluri);
293 pop_string(msg, &msg->add_ca.crluri2);
294 pop_string(msg, &msg->add_ca.ocspuri);
295 pop_string(msg, &msg->add_ca.ocspuri2);
296 pop_string(msg, &msg->add_ca.certuribase);
297 DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
298 DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert);
299 DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri);
300 DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2);
301 DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri);
302 DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2);
303 DBG2(DBG_CFG, " certuribase=%s", msg->add_ca.certuribase);
304
305 this->ca->add(this->ca, msg);
306 }
307
308 /**
309 * Delete a ca information record from the cainfo list
310 */
311 static void stroke_del_ca(private_stroke_socket_t *this,
312 stroke_msg_t *msg, FILE *out)
313 {
314 pop_string(msg, &msg->del_ca.name);
315 DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
316
317 this->ca->del(this->ca, msg);
318 }
319
320
321 /**
322 * show status of daemon
323 */
324 static void stroke_status(private_stroke_socket_t *this,
325 stroke_msg_t *msg, FILE *out, bool all, bool wait)
326 {
327 pop_string(msg, &(msg->status.name));
328
329 this->list->status(this->list, msg, out, all, wait);
330 }
331
332 /**
333 * list various information
334 */
335 static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
336 {
337 if (msg->list.flags & LIST_CAINFOS)
338 {
339 this->ca->list(this->ca, msg, out);
340 }
341 this->list->list(this->list, msg, out);
342 }
343
344 /**
345 * reread various information
346 */
347 static void stroke_reread(private_stroke_socket_t *this,
348 stroke_msg_t *msg, FILE *out)
349 {
350 this->cred->reread(this->cred, msg, out);
351 }
352
353 /**
354 * purge various information
355 */
356 static void stroke_purge(private_stroke_socket_t *this,
357 stroke_msg_t *msg, FILE *out)
358 {
359 if (msg->purge.flags & PURGE_OCSP)
360 {
361 lib->credmgr->flush_cache(lib->credmgr, CERT_X509_OCSP_RESPONSE);
362 }
363 if (msg->purge.flags & PURGE_CRLS)
364 {
365 lib->credmgr->flush_cache(lib->credmgr, CERT_X509_CRL);
366 }
367 if (msg->purge.flags & PURGE_CERTS)
368 {
369 lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
370 }
371 if (msg->purge.flags & PURGE_IKE)
372 {
373 this->control->purge_ike(this->control, msg, out);
374 }
375 }
376
377 /**
378 * Export in-memory credentials
379 */
380 static void stroke_export(private_stroke_socket_t *this,
381 stroke_msg_t *msg, FILE *out)
382 {
383 pop_string(msg, &msg->export.selector);
384
385 if (msg->purge.flags & EXPORT_X509)
386 {
387 enumerator_t *enumerator;
388 identification_t *id;
389 certificate_t *cert;
390 chunk_t encoded;
391
392 id = identification_create_from_string(msg->export.selector);
393 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
394 CERT_X509, KEY_ANY, id, FALSE);
395 while (enumerator->enumerate(enumerator, &cert))
396 {
397 if (cert->get_encoding(cert, CERT_PEM, &encoded))
398 {
399 fprintf(out, "%.*s", (int)encoded.len, encoded.ptr);
400 free(encoded.ptr);
401 }
402 }
403 enumerator->destroy(enumerator);
404 id->destroy(id);
405 }
406 }
407
408 /**
409 * list pool leases
410 */
411 static void stroke_leases(private_stroke_socket_t *this,
412 stroke_msg_t *msg, FILE *out)
413 {
414 pop_string(msg, &msg->leases.pool);
415 pop_string(msg, &msg->leases.address);
416
417 this->list->leases(this->list, msg, out);
418 }
419
420 /**
421 * Show memory usage
422 */
423 static void stroke_memusage(private_stroke_socket_t *this,
424 stroke_msg_t *msg, FILE *out)
425 {
426 if (lib->leak_detective)
427 {
428 lib->leak_detective->usage(lib->leak_detective, out);
429 }
430 }
431
432 /**
433 * set the verbosity debug output
434 */
435 static void stroke_loglevel(private_stroke_socket_t *this,
436 stroke_msg_t *msg, FILE *out)
437 {
438 enumerator_t *enumerator;
439 sys_logger_t *sys_logger;
440 file_logger_t *file_logger;
441 debug_t group;
442
443 pop_string(msg, &(msg->loglevel.type));
444 DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
445 msg->loglevel.level, msg->loglevel.type);
446
447 group = enum_from_name(debug_names, msg->loglevel.type);
448 if (group < 0)
449 {
450 fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
451 return;
452 }
453 /* we set the loglevel on ALL sys- and file-loggers */
454 enumerator = charon->sys_loggers->create_enumerator(charon->sys_loggers);
455 while (enumerator->enumerate(enumerator, &sys_logger))
456 {
457 sys_logger->set_level(sys_logger, group, msg->loglevel.level);
458 }
459 enumerator->destroy(enumerator);
460 enumerator = charon->file_loggers->create_enumerator(charon->file_loggers);
461 while (enumerator->enumerate(enumerator, &file_logger))
462 {
463 file_logger->set_level(file_logger, group, msg->loglevel.level);
464 }
465 enumerator->destroy(enumerator);
466 }
467
468 /**
469 * set various config options
470 */
471 static void stroke_config(private_stroke_socket_t *this,
472 stroke_msg_t *msg, FILE *out)
473 {
474 this->cred->cachecrl(this->cred, msg->config.cachecrl);
475 }
476
477 /**
478 * destroy a job context
479 */
480 static void stroke_job_context_destroy(stroke_job_context_t *this)
481 {
482 if (this->fd)
483 {
484 close(this->fd);
485 }
486 free(this);
487 }
488
489 /**
490 * process a stroke request from the socket pointed by "fd"
491 */
492 static job_requeue_t process(stroke_job_context_t *ctx)
493 {
494 stroke_msg_t *msg;
495 u_int16_t msg_length;
496 ssize_t bytes_read;
497 FILE *out;
498 private_stroke_socket_t *this = ctx->this;
499 int strokefd = ctx->fd;
500
501 /* peek the length */
502 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
503 if (bytes_read != sizeof(msg_length))
504 {
505 DBG1(DBG_CFG, "reading length of stroke message failed: %s",
506 strerror(errno));
507 return JOB_REQUEUE_NONE;
508 }
509
510 /* read message */
511 msg = alloca(msg_length);
512 bytes_read = recv(strokefd, msg, msg_length, 0);
513 if (bytes_read != msg_length)
514 {
515 DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
516 return JOB_REQUEUE_NONE;
517 }
518
519 out = fdopen(strokefd, "w+");
520 if (out == NULL)
521 {
522 DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
523 return JOB_REQUEUE_NONE;
524 }
525
526 DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
527
528 switch (msg->type)
529 {
530 case STR_INITIATE:
531 stroke_initiate(this, msg, out);
532 break;
533 case STR_ROUTE:
534 stroke_route(this, msg, out);
535 break;
536 case STR_UNROUTE:
537 stroke_unroute(this, msg, out);
538 break;
539 case STR_TERMINATE:
540 stroke_terminate(this, msg, out);
541 break;
542 case STR_TERMINATE_SRCIP:
543 stroke_terminate_srcip(this, msg, out);
544 break;
545 case STR_REKEY:
546 stroke_rekey(this, msg, out);
547 break;
548 case STR_STATUS:
549 stroke_status(this, msg, out, FALSE, TRUE);
550 break;
551 case STR_STATUS_ALL:
552 stroke_status(this, msg, out, TRUE, TRUE);
553 break;
554 case STR_STATUS_ALL_NOBLK:
555 stroke_status(this, msg, out, TRUE, FALSE);
556 break;
557 case STR_ADD_CONN:
558 stroke_add_conn(this, msg);
559 break;
560 case STR_DEL_CONN:
561 stroke_del_conn(this, msg);
562 break;
563 case STR_ADD_CA:
564 stroke_add_ca(this, msg, out);
565 break;
566 case STR_DEL_CA:
567 stroke_del_ca(this, msg, out);
568 break;
569 case STR_LOGLEVEL:
570 stroke_loglevel(this, msg, out);
571 break;
572 case STR_CONFIG:
573 stroke_config(this, msg, out);
574 break;
575 case STR_LIST:
576 stroke_list(this, msg, out);
577 break;
578 case STR_REREAD:
579 stroke_reread(this, msg, out);
580 break;
581 case STR_PURGE:
582 stroke_purge(this, msg, out);
583 break;
584 case STR_EXPORT:
585 stroke_export(this, msg, out);
586 break;
587 case STR_LEASES:
588 stroke_leases(this, msg, out);
589 break;
590 case STR_MEMUSAGE:
591 stroke_memusage(this, msg, out);
592 break;
593 default:
594 DBG1(DBG_CFG, "received unknown stroke");
595 break;
596 }
597 fclose(out);
598 /* fclose() closes underlying FD */
599 ctx->fd = 0;
600 return JOB_REQUEUE_NONE;
601 }
602
603 /**
604 * Implementation of private_stroke_socket_t.stroke_receive.
605 */
606 static job_requeue_t receive(private_stroke_socket_t *this)
607 {
608 struct sockaddr_un strokeaddr;
609 int strokeaddrlen = sizeof(strokeaddr);
610 int strokefd;
611 bool oldstate;
612 callback_job_t *job;
613 stroke_job_context_t *ctx;
614
615 oldstate = thread_cancelability(TRUE);
616 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
617 thread_cancelability(oldstate);
618
619 if (strokefd < 0)
620 {
621 DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
622 return JOB_REQUEUE_FAIR;
623 }
624
625 ctx = malloc_thing(stroke_job_context_t);
626 ctx->fd = strokefd;
627 ctx->this = this;
628 job = callback_job_create_with_prio((callback_job_cb_t)process,
629 ctx, (void*)stroke_job_context_destroy, this->job, JOB_PRIO_HIGH);
630 lib->processor->queue_job(lib->processor, (job_t*)job);
631
632 return JOB_REQUEUE_FAIR;
633 }
634
635
636 /**
637 * initialize and open stroke socket
638 */
639 static bool open_socket(private_stroke_socket_t *this)
640 {
641 struct sockaddr_un socket_addr;
642 mode_t old;
643
644 socket_addr.sun_family = AF_UNIX;
645 strcpy(socket_addr.sun_path, STROKE_SOCKET);
646
647 /* set up unix socket */
648 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
649 if (this->socket == -1)
650 {
651 DBG1(DBG_CFG, "could not create stroke socket");
652 return FALSE;
653 }
654
655 unlink(socket_addr.sun_path);
656 old = umask(~(S_IRWXU | S_IRWXG));
657 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
658 {
659 DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
660 close(this->socket);
661 return FALSE;
662 }
663 umask(old);
664 if (chown(socket_addr.sun_path, charon->uid, charon->gid) != 0)
665 {
666 DBG1(DBG_CFG, "changing stroke socket permissions failed: %s",
667 strerror(errno));
668 }
669
670 if (listen(this->socket, 10) < 0)
671 {
672 DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
673 close(this->socket);
674 unlink(socket_addr.sun_path);
675 return FALSE;
676 }
677 return TRUE;
678 }
679
680 /**
681 * Implementation of stroke_socket_t.destroy
682 */
683 static void destroy(private_stroke_socket_t *this)
684 {
685 this->job->cancel(this->job);
686 lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
687 lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
688 charon->backends->remove_backend(charon->backends, &this->config->backend);
689 hydra->attributes->remove_provider(hydra->attributes, &this->attribute->provider);
690 this->cred->destroy(this->cred);
691 this->ca->destroy(this->ca);
692 this->config->destroy(this->config);
693 this->attribute->destroy(this->attribute);
694 this->control->destroy(this->control);
695 this->list->destroy(this->list);
696 free(this);
697 }
698
699 /*
700 * see header file
701 */
702 stroke_socket_t *stroke_socket_create()
703 {
704 private_stroke_socket_t *this = malloc_thing(private_stroke_socket_t);
705
706 this->public.destroy = (void(*)(stroke_socket_t*))destroy;
707
708 if (!open_socket(this))
709 {
710 free(this);
711 return NULL;
712 }
713
714 this->cred = stroke_cred_create();
715 this->attribute = stroke_attribute_create();
716 this->ca = stroke_ca_create(this->cred);
717 this->config = stroke_config_create(this->ca, this->cred);
718 this->control = stroke_control_create();
719 this->list = stroke_list_create(this->attribute);
720
721 lib->credmgr->add_set(lib->credmgr, &this->ca->set);
722 lib->credmgr->add_set(lib->credmgr, &this->cred->set);
723 charon->backends->add_backend(charon->backends, &this->config->backend);
724 hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
725
726 this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
727 this, NULL, NULL, JOB_PRIO_CRITICAL);
728 lib->processor->queue_job(lib->processor, (job_t*)this->job);
729
730 return &this->public;
731 }
732