Simplified logging of list of loaded plugins.
[strongswan.git] / src / libcharon / plugins / stroke / stroke_list.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_list.h"
17
18 #include <inttypes.h>
19 #include <time.h>
20
21 #ifdef HAVE_MALLINFO
22 #include <malloc.h>
23 #endif /* HAVE_MALLINFO */
24
25 #include <hydra.h>
26 #include <daemon.h>
27 #include <utils/linked_list.h>
28 #include <plugins/plugin.h>
29 #include <credentials/certificates/x509.h>
30 #include <credentials/certificates/ac.h>
31 #include <credentials/certificates/crl.h>
32 #include <credentials/certificates/pgp_certificate.h>
33 #include <credentials/ietf_attributes/ietf_attributes.h>
34 #include <config/peer_cfg.h>
35
36 /* warning intervals for list functions */
37 #define CERT_WARNING_INTERVAL 30 /* days */
38 #define CRL_WARNING_INTERVAL 7 /* days */
39 #define AC_WARNING_INTERVAL 1 /* day */
40
41 typedef struct private_stroke_list_t private_stroke_list_t;
42
43 /**
44 * private data of stroke_list
45 */
46 struct private_stroke_list_t {
47
48 /**
49 * public functions
50 */
51 stroke_list_t public;
52
53 /**
54 * timestamp of daemon start
55 */
56 time_t uptime;
57
58 /**
59 * strokes attribute provider
60 */
61 stroke_attribute_t *attribute;
62 };
63
64 /**
65 * Log tasks of a specific queue to out
66 */
67 static void log_task_q(FILE *out, ike_sa_t *ike_sa, task_queue_t q, char *name)
68 {
69 enumerator_t *enumerator;
70 bool has = FALSE;
71 task_t *task;
72
73 enumerator = ike_sa->create_task_enumerator(ike_sa, q);
74 while (enumerator->enumerate(enumerator, &task))
75 {
76 if (!has)
77 {
78 fprintf(out, "%12s[%d]: Tasks %s: ", ike_sa->get_name(ike_sa),
79 ike_sa->get_unique_id(ike_sa), name);
80 has = TRUE;
81 }
82 fprintf(out, "%N ", task_type_names, task->get_type(task));
83 }
84 enumerator->destroy(enumerator);
85 if (has)
86 {
87 fprintf(out, "\n");
88 }
89 }
90
91 /**
92 * log an IKE_SA to out
93 */
94 static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
95 {
96 ike_sa_id_t *id = ike_sa->get_id(ike_sa);
97 time_t now = time_monotonic(NULL);
98
99 fprintf(out, "%12s[%d]: %N",
100 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
101 ike_sa_state_names, ike_sa->get_state(ike_sa));
102
103 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
104 {
105 time_t established;
106
107 established = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED);
108 fprintf(out, " %V ago", &now, &established);
109 }
110
111 fprintf(out, ", %H[%Y]...%H[%Y]\n",
112 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
113 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
114
115 if (all)
116 {
117 proposal_t *ike_proposal;
118
119 ike_proposal = ike_sa->get_proposal(ike_sa);
120
121 fprintf(out, "%12s[%d]: IKE SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s",
122 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
123 id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
124 id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
125
126
127 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
128 {
129 time_t rekey, reauth;
130 peer_cfg_t *peer_cfg;
131
132 rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY);
133 reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH);
134 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
135
136 if (rekey)
137 {
138 fprintf(out, ", rekeying in %V", &rekey, &now);
139 }
140 if (reauth)
141 {
142 bool first = TRUE;
143 enumerator_t *enumerator;
144 auth_cfg_t *auth;
145
146 fprintf(out, ", ");
147 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, TRUE);
148 while (enumerator->enumerate(enumerator, &auth))
149 {
150 if (!first)
151 {
152 fprintf(out, "+");
153 }
154 first = FALSE;
155 fprintf(out, "%N", auth_class_names,
156 auth->get(auth, AUTH_RULE_AUTH_CLASS));
157 }
158 enumerator->destroy(enumerator);
159 fprintf(out, " reauthentication in %V", &reauth, &now);
160 }
161 if (!rekey && !reauth)
162 {
163 fprintf(out, ", rekeying disabled");
164 }
165 }
166 fprintf(out, "\n");
167
168 if (ike_proposal)
169 {
170 char buf[BUF_LEN];
171
172 snprintf(buf, BUF_LEN, "%P", ike_proposal);
173 fprintf(out, "%12s[%d]: IKE proposal: %s\n",
174 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
175 buf+4);
176 }
177
178 log_task_q(out, ike_sa, TASK_QUEUE_QUEUED, "queued");
179 log_task_q(out, ike_sa, TASK_QUEUE_ACTIVE, "active");
180 log_task_q(out, ike_sa, TASK_QUEUE_PASSIVE, "passive");
181 }
182 }
183
184 /**
185 * log an CHILD_SA to out
186 */
187 static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
188 {
189 time_t use_in, use_out, rekey, now;
190 u_int64_t bytes_in, bytes_out;
191 proposal_t *proposal;
192 child_cfg_t *config = child_sa->get_config(child_sa);
193
194
195 fprintf(out, "%12s{%d}: %N, %N%s",
196 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
197 child_sa_state_names, child_sa->get_state(child_sa),
198 ipsec_mode_names, child_sa->get_mode(child_sa),
199 config->use_proxy_mode(config) ? "_PROXY" : "");
200
201 if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
202 {
203 fprintf(out, ", %N%s SPIs: %.8x_i %.8x_o",
204 protocol_id_names, child_sa->get_protocol(child_sa),
205 child_sa->has_encap(child_sa) ? " in UDP" : "",
206 ntohl(child_sa->get_spi(child_sa, TRUE)),
207 ntohl(child_sa->get_spi(child_sa, FALSE)));
208
209 if (child_sa->get_ipcomp(child_sa) != IPCOMP_NONE)
210 {
211 fprintf(out, ", IPCOMP CPIs: %.4x_i %.4x_o",
212 ntohs(child_sa->get_cpi(child_sa, TRUE)),
213 ntohs(child_sa->get_cpi(child_sa, FALSE)));
214 }
215
216 if (all)
217 {
218 fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa),
219 child_sa->get_reqid(child_sa));
220
221 proposal = child_sa->get_proposal(child_sa);
222 if (proposal)
223 {
224 u_int16_t encr_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED;
225 u_int16_t encr_size = 0, int_size = 0;
226 u_int16_t esn = NO_EXT_SEQ_NUMBERS;
227
228 proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
229 &encr_alg, &encr_size);
230 proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
231 &int_alg, &int_size);
232 proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS,
233 &esn, NULL);
234
235 if (encr_alg != ENCR_UNDEFINED)
236 {
237 fprintf(out, "%N", encryption_algorithm_names, encr_alg);
238 if (encr_size)
239 {
240 fprintf(out, "_%u", encr_size);
241 }
242 }
243 if (int_alg != AUTH_UNDEFINED)
244 {
245 fprintf(out, "/%N", integrity_algorithm_names, int_alg);
246 if (int_size)
247 {
248 fprintf(out, "_%u", int_size);
249 }
250 }
251 if (esn == EXT_SEQ_NUMBERS)
252 {
253 fprintf(out, "/ESN");
254 }
255 }
256
257 now = time_monotonic(NULL);
258 child_sa->get_usestats(child_sa, TRUE, &use_in, &bytes_in);
259 fprintf(out, ", %" PRIu64 " bytes_i", bytes_in);
260 if (use_in)
261 {
262 fprintf(out, " (%" PRIu64 "s ago)", (u_int64_t)(now - use_in));
263 }
264
265 child_sa->get_usestats(child_sa, FALSE, &use_out, &bytes_out);
266 fprintf(out, ", %" PRIu64 " bytes_o", bytes_out);
267 if (use_out)
268 {
269 fprintf(out, " (%" PRIu64 "s ago)", (u_int64_t)(now - use_out));
270 }
271 fprintf(out, ", rekeying ");
272
273 rekey = child_sa->get_lifetime(child_sa, FALSE);
274 if (rekey)
275 {
276 if (now > rekey)
277 {
278 fprintf(out, "active");
279 }
280 else
281 {
282 fprintf(out, "in %V", &now, &rekey);
283 }
284 }
285 else
286 {
287 fprintf(out, "disabled");
288 }
289
290 }
291 }
292
293 fprintf(out, "\n%12s{%d}: %#R=== %#R\n",
294 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
295 child_sa->get_traffic_selectors(child_sa, TRUE),
296 child_sa->get_traffic_selectors(child_sa, FALSE));
297 }
298
299 /**
300 * Log a configs local or remote authentication config to out
301 */
302 static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local)
303 {
304 enumerator_t *enumerator, *rules;
305 auth_rule_t rule;
306 auth_cfg_t *auth;
307 auth_class_t auth_class;
308 identification_t *id;
309 certificate_t *cert;
310 cert_validation_t valid;
311 char *name;
312
313 name = peer_cfg->get_name(peer_cfg);
314
315 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
316 while (enumerator->enumerate(enumerator, &auth))
317 {
318 fprintf(out, "%12s: %s [%Y] uses ", name, local ? "local: " : "remote:",
319 auth->get(auth, AUTH_RULE_IDENTITY));
320
321 auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
322 if (auth_class != AUTH_CLASS_EAP)
323 {
324 fprintf(out, "%N authentication\n", auth_class_names, auth_class);
325 }
326 else
327 {
328 if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK)
329 {
330 fprintf(out, "EAP authentication");
331 }
332 else
333 {
334 if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR))
335 {
336 fprintf(out, "EAP_%" PRIuPTR "-%" PRIuPTR " authentication",
337 (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE),
338 (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR));
339 }
340 else
341 {
342 fprintf(out, "%N authentication", eap_type_names,
343 (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE));
344 }
345 }
346 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
347 if (id)
348 {
349 fprintf(out, " with EAP identity '%Y'", id);
350 }
351 fprintf(out, "\n");
352 }
353
354 cert = auth->get(auth, AUTH_RULE_CA_CERT);
355 if (cert)
356 {
357 fprintf(out, "%12s: ca: \"%Y\"\n", name, cert->get_subject(cert));
358 }
359
360 cert = auth->get(auth, AUTH_RULE_IM_CERT);
361 if (cert)
362 {
363 fprintf(out, "%12s: im-ca: \"%Y\"\n", name, cert->get_subject(cert));
364 }
365
366 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
367 if (cert)
368 {
369 fprintf(out, "%12s: cert: \"%Y\"\n", name,
370 cert->get_subject(cert));
371 }
372
373 valid = (uintptr_t)auth->get(auth, AUTH_RULE_OCSP_VALIDATION);
374 if (valid != VALIDATION_FAILED)
375 {
376 fprintf(out, "%12s: ocsp: status must be GOOD%s\n", name,
377 (valid == VALIDATION_SKIPPED) ? " or SKIPPED" : "");
378 }
379
380 valid = (uintptr_t)auth->get(auth, AUTH_RULE_CRL_VALIDATION);
381 if (valid != VALIDATION_FAILED)
382 {
383 fprintf(out, "%12s: crl: status must be GOOD%s\n", name,
384 (valid == VALIDATION_SKIPPED) ? " or SKIPPED" : "");
385 }
386
387 rules = auth->create_enumerator(auth);
388 while (rules->enumerate(rules, &rule, &id))
389 {
390 if (rule == AUTH_RULE_GROUP)
391 {
392 fprintf(out, "%12s: group: %Y\n", name, id);
393 }
394 }
395 rules->destroy(rules);
396 }
397 enumerator->destroy(enumerator);
398 }
399
400 METHOD(stroke_list_t, status, void,
401 private_stroke_list_t *this, stroke_msg_t *msg, FILE *out,
402 bool all, bool wait)
403 {
404 enumerator_t *enumerator, *children;
405 ike_cfg_t *ike_cfg;
406 child_cfg_t *child_cfg;
407 child_sa_t *child_sa;
408 ike_sa_t *ike_sa;
409 linked_list_t *my_ts, *other_ts;
410 bool first, found = FALSE;
411 char *name = msg->status.name;
412 u_int half_open;
413
414 if (all)
415 {
416 peer_cfg_t *peer_cfg;
417 plugin_t *plugin;
418 char *pool, *plugins;
419 host_t *host;
420 u_int32_t dpd;
421 time_t since, now;
422 u_int size, online, offline, i;
423 now = time_monotonic(NULL);
424 since = time(NULL) - (now - this->uptime);
425
426 fprintf(out, "Status of IKEv2 charon daemon (strongSwan "VERSION"):\n");
427 fprintf(out, " uptime: %V, since %T\n", &now, &this->uptime, &since, FALSE);
428 #ifdef HAVE_MALLINFO
429 {
430 struct mallinfo mi = mallinfo();
431
432 fprintf(out, " malloc: sbrk %d, mmap %d, used %d, free %d\n",
433 mi.arena, mi.hblkhd, mi.uordblks, mi.fordblks);
434 }
435 #endif /* HAVE_MALLINFO */
436 fprintf(out, " worker threads: %d of %d idle, ",
437 lib->processor->get_idle_threads(lib->processor),
438 lib->processor->get_total_threads(lib->processor));
439 for (i = 0; i < JOB_PRIO_MAX; i++)
440 {
441 fprintf(out, "%s%d", i == 0 ? "" : "/",
442 lib->processor->get_working_threads(lib->processor, i));
443 }
444 fprintf(out, " working, job queue: ");
445 for (i = 0; i < JOB_PRIO_MAX; i++)
446 {
447 fprintf(out, "%s%d", i == 0 ? "" : "/",
448 lib->processor->get_job_load(lib->processor, i));
449 }
450 fprintf(out, ", scheduled: %d\n",
451 lib->scheduler->get_job_load(lib->scheduler));
452 plugins = lib->plugins->loaded_plugins(lib->plugins);
453 fprintf(out, " loaded plugins: %s\n", plugins);
454 free(plugins);
455
456 first = TRUE;
457 enumerator = this->attribute->create_pool_enumerator(this->attribute);
458 while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline))
459 {
460 if (name && !streq(name, pool))
461 {
462 continue;
463 }
464 if (first)
465 {
466 first = FALSE;
467 fprintf(out, "Virtual IP pools (size/online/offline):\n");
468 }
469 fprintf(out, " %s: %u/%u/%u\n", pool, size, online, offline);
470 }
471 enumerator->destroy(enumerator);
472
473 enumerator = hydra->kernel_interface->create_address_enumerator(
474 hydra->kernel_interface, FALSE, FALSE);
475 fprintf(out, "Listening IP addresses:\n");
476 while (enumerator->enumerate(enumerator, (void**)&host))
477 {
478 fprintf(out, " %H\n", host);
479 }
480 enumerator->destroy(enumerator);
481
482 fprintf(out, "Connections:\n");
483 enumerator = charon->backends->create_peer_cfg_enumerator(
484 charon->backends, NULL, NULL, NULL, NULL);
485 while (enumerator->enumerate(enumerator, &peer_cfg))
486 {
487 if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
488 (name && !streq(name, peer_cfg->get_name(peer_cfg))))
489 {
490 continue;
491 }
492
493 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
494 fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg),
495 ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg));
496
497 dpd = peer_cfg->get_dpd(peer_cfg);
498 if (dpd)
499 {
500 fprintf(out, ", dpddelay=%us", dpd);
501 }
502 fprintf(out, "\n");
503
504 log_auth_cfgs(out, peer_cfg, TRUE);
505 log_auth_cfgs(out, peer_cfg, FALSE);
506
507 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
508 while (children->enumerate(children, &child_cfg))
509 {
510 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
511 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
512 fprintf(out, "%12s: child: %#R=== %#R%N",
513 child_cfg->get_name(child_cfg), my_ts, other_ts,
514 ipsec_mode_names, child_cfg->get_mode(child_cfg));
515 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
516 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
517
518 if (dpd)
519 {
520 fprintf(out, ", dpdaction=%N", action_names,
521 child_cfg->get_dpd_action(child_cfg));
522 }
523 fprintf(out, "\n");
524 }
525 children->destroy(children);
526 }
527 enumerator->destroy(enumerator);
528 }
529
530 /* Enumerate shunt policies */
531 first = TRUE;
532 enumerator = charon->shunts->create_enumerator(charon->shunts);
533 while (enumerator->enumerate(enumerator, &child_cfg))
534 {
535 if (name && !streq(name, child_cfg->get_name(child_cfg)))
536 {
537 continue;
538 }
539 if (first)
540 {
541 fprintf(out, "Shunted Connections:\n");
542 first = FALSE;
543 }
544 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
545 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
546 fprintf(out, "%12s: %#R=== %#R%N\n",
547 child_cfg->get_name(child_cfg), my_ts, other_ts,
548 ipsec_mode_names, child_cfg->get_mode(child_cfg));
549 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
550 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
551 }
552 enumerator->destroy(enumerator);
553
554 /* Enumerate traps */
555 first = TRUE;
556 enumerator = charon->traps->create_enumerator(charon->traps);
557 while (enumerator->enumerate(enumerator, NULL, &child_sa))
558 {
559 if (name && !streq(name, child_sa->get_name(child_sa)))
560 {
561 continue;
562 }
563 if (first)
564 {
565 fprintf(out, "Routed Connections:\n");
566 first = FALSE;
567 }
568 log_child_sa(out, child_sa, all);
569 }
570 enumerator->destroy(enumerator);
571
572 half_open = charon->ike_sa_manager->get_half_open_count(
573 charon->ike_sa_manager, NULL);
574 fprintf(out, "Security Associations (%u up, %u connecting):\n",
575 charon->ike_sa_manager->get_count(charon->ike_sa_manager) - half_open,
576 half_open);
577 enumerator = charon->controller->create_ike_sa_enumerator(
578 charon->controller, wait);
579 while (enumerator->enumerate(enumerator, &ike_sa))
580 {
581 bool ike_printed = FALSE;
582 enumerator_t *children = ike_sa->create_child_sa_enumerator(ike_sa);
583
584 if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
585 {
586 log_ike_sa(out, ike_sa, all);
587 found = TRUE;
588 ike_printed = TRUE;
589 }
590
591 while (children->enumerate(children, (void**)&child_sa))
592 {
593 if (name == NULL || streq(name, child_sa->get_name(child_sa)))
594 {
595 if (!ike_printed)
596 {
597 log_ike_sa(out, ike_sa, all);
598 found = TRUE;
599 ike_printed = TRUE;
600 }
601 log_child_sa(out, child_sa, all);
602 }
603 }
604 children->destroy(children);
605 }
606 enumerator->destroy(enumerator);
607
608 if (!found)
609 {
610 if (name)
611 {
612 fprintf(out, " no match\n");
613 }
614 else
615 {
616 fprintf(out, " none\n");
617 }
618 }
619 }
620
621 /**
622 * create a unique certificate list without duplicates
623 * certicates having the same issuer are grouped together.
624 */
625 static linked_list_t* create_unique_cert_list(certificate_type_t type)
626 {
627 linked_list_t *list = linked_list_create();
628 enumerator_t *enumerator = lib->credmgr->create_cert_enumerator(
629 lib->credmgr, type, KEY_ANY, NULL, FALSE);
630 certificate_t *cert;
631
632 while (enumerator->enumerate(enumerator, (void**)&cert))
633 {
634 enumerator_t *added = list->create_enumerator(list);
635 identification_t *issuer = cert->get_issuer(cert);
636 bool previous_same, same = FALSE, found = FALSE;
637 certificate_t *list_cert;
638
639 while (added->enumerate(added, (void**)&list_cert))
640 {
641 if (list_cert->equals(list_cert, cert))
642 { /* stop if we found a duplicate*/
643 found = TRUE;
644 break;
645 }
646 previous_same = same;
647 same = list_cert->has_issuer(list_cert, issuer);
648 if (previous_same && !same)
649 { /* group certificates with same issuer */
650 break;
651 }
652 }
653 if (!found)
654 {
655 list->insert_before(list, added, cert->get_ref(cert));
656 }
657 added->destroy(added);
658 }
659 enumerator->destroy(enumerator);
660 return list;
661 }
662
663 /**
664 * Print a single public key.
665 */
666 static void list_public_key(public_key_t *public, FILE *out)
667 {
668 private_key_t *private = NULL;
669 chunk_t keyid;
670 identification_t *id;
671 auth_cfg_t *auth;
672
673 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
674 {
675 id = identification_create_from_encoding(ID_KEY_ID, keyid);
676 auth = auth_cfg_create();
677 private = lib->credmgr->get_private(lib->credmgr,
678 public->get_type(public), id, auth);
679 auth->destroy(auth);
680 id->destroy(id);
681 }
682
683 fprintf(out, " pubkey: %N %d bits%s\n",
684 key_type_names, public->get_type(public),
685 public->get_keysize(public),
686 private ? ", has private key" : "");
687 if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
688 {
689 fprintf(out, " keyid: %#B\n", &keyid);
690 }
691 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
692 {
693 fprintf(out, " subjkey: %#B\n", &keyid);
694 }
695 DESTROY_IF(private);
696 }
697
698 /**
699 * list all raw public keys
700 */
701 static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out)
702 {
703 bool first = TRUE;
704
705 enumerator_t *enumerator = list->create_enumerator(list);
706 certificate_t *cert;
707
708 while (enumerator->enumerate(enumerator, (void**)&cert))
709 {
710 public_key_t *public = cert->get_public_key(cert);
711
712 if (public)
713 {
714 if (first)
715 {
716 fprintf(out, "\n");
717 fprintf(out, "List of Raw Public Keys:\n");
718 first = FALSE;
719 }
720 fprintf(out, "\n");
721
722 list_public_key(public, out);
723 public->destroy(public);
724 }
725 }
726 enumerator->destroy(enumerator);
727 }
728
729 /**
730 * list OpenPGP certificates
731 */
732 static void stroke_list_pgp(linked_list_t *list,bool utc, FILE *out)
733 {
734 bool first = TRUE;
735 time_t now = time(NULL);
736 enumerator_t *enumerator = list->create_enumerator(list);
737 certificate_t *cert;
738
739 while (enumerator->enumerate(enumerator, (void**)&cert))
740 {
741 time_t created, until;
742 public_key_t *public;
743 pgp_certificate_t *pgp_cert = (pgp_certificate_t*)cert;
744 chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert);
745
746 if (first)
747 {
748
749 fprintf(out, "\n");
750 fprintf(out, "List of PGP End Entity Certificates:\n");
751 first = FALSE;
752 }
753 fprintf(out, "\n");
754 fprintf(out, " userid: '%Y'\n", cert->get_subject(cert));
755
756 fprintf(out, " digest: %#B\n", &fingerprint);
757
758 /* list validity */
759 cert->get_validity(cert, &now, &created, &until);
760 fprintf(out, " created: %T\n", &created, utc);
761 fprintf(out, " until: %T%s\n", &until, utc,
762 (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":"");
763
764 public = cert->get_public_key(cert);
765 if (public)
766 {
767 list_public_key(public, out);
768 public->destroy(public);
769 }
770 }
771 enumerator->destroy(enumerator);
772 }
773
774 /**
775 * list all X.509 certificates matching the flags
776 */
777 static void stroke_list_certs(linked_list_t *list, char *label,
778 x509_flag_t flags, bool utc, FILE *out)
779 {
780 bool first = TRUE;
781 time_t now = time(NULL);
782 enumerator_t *enumerator;
783 certificate_t *cert;
784 x509_flag_t flag_mask;
785
786 /* mask all auxiliary flags */
787 flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH |
788 X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS );
789
790 enumerator = list->create_enumerator(list);
791 while (enumerator->enumerate(enumerator, (void**)&cert))
792 {
793 x509_t *x509 = (x509_t*)cert;
794 x509_flag_t x509_flags = x509->get_flags(x509) & flag_mask;
795
796 /* list only if flag is set or flag == 0 */
797 if ((x509_flags & flags) || (x509_flags == flags))
798 {
799 enumerator_t *enumerator;
800 identification_t *altName;
801 bool first_altName = TRUE;
802 u_int pathlen;
803 chunk_t serial, authkey;
804 time_t notBefore, notAfter;
805 public_key_t *public;
806
807 if (first)
808 {
809 fprintf(out, "\n");
810 fprintf(out, "List of %s:\n", label);
811 first = FALSE;
812 }
813 fprintf(out, "\n");
814
815 /* list subjectAltNames */
816 enumerator = x509->create_subjectAltName_enumerator(x509);
817 while (enumerator->enumerate(enumerator, (void**)&altName))
818 {
819 if (first_altName)
820 {
821 fprintf(out, " altNames: ");
822 first_altName = FALSE;
823 }
824 else
825 {
826 fprintf(out, ", ");
827 }
828 fprintf(out, "%Y", altName);
829 }
830 if (!first_altName)
831 {
832 fprintf(out, "\n");
833 }
834 enumerator->destroy(enumerator);
835
836 fprintf(out, " subject: \"%Y\"\n", cert->get_subject(cert));
837 fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
838 serial = x509->get_serial(x509);
839 fprintf(out, " serial: %#B\n", &serial);
840
841 /* list validity */
842 cert->get_validity(cert, &now, &notBefore, &notAfter);
843 fprintf(out, " validity: not before %T, ", &notBefore, utc);
844 if (now < notBefore)
845 {
846 fprintf(out, "not valid yet (valid in %V)\n", &now, &notBefore);
847 }
848 else
849 {
850 fprintf(out, "ok\n");
851 }
852 fprintf(out, " not after %T, ", &notAfter, utc);
853 if (now > notAfter)
854 {
855 fprintf(out, "expired (%V ago)\n", &now, &notAfter);
856 }
857 else
858 {
859 fprintf(out, "ok");
860 if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
861 {
862 fprintf(out, " (expires in %V)", &now, &notAfter);
863 }
864 fprintf(out, " \n");
865 }
866
867 public = cert->get_public_key(cert);
868 if (public)
869 {
870 list_public_key(public, out);
871 public->destroy(public);
872 }
873
874 /* list optional authorityKeyIdentifier */
875 authkey = x509->get_authKeyIdentifier(x509);
876 if (authkey.ptr)
877 {
878 fprintf(out, " authkey: %#B\n", &authkey);
879 }
880
881 /* list optional pathLenConstraint */
882 pathlen = x509->get_constraint(x509, X509_PATH_LEN);
883 if (pathlen != X509_NO_CONSTRAINT)
884 {
885 fprintf(out, " pathlen: %u\n", pathlen);
886 }
887
888 /* list optional ipAddrBlocks */
889 if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS)
890 {
891 traffic_selector_t *ipAddrBlock;
892 bool first_ipAddrBlock = TRUE;
893
894 fprintf(out, " addresses: ");
895 enumerator = x509->create_ipAddrBlock_enumerator(x509);
896 while (enumerator->enumerate(enumerator, &ipAddrBlock))
897 {
898 if (first_ipAddrBlock)
899 {
900 first_ipAddrBlock = FALSE;
901 }
902 else
903 {
904 fprintf(out, ", ");
905 }
906 fprintf(out, "%R", ipAddrBlock);
907 }
908 enumerator->destroy(enumerator);
909 fprintf(out, "\n");
910 }
911 }
912 }
913 enumerator->destroy(enumerator);
914 }
915
916 /**
917 * list all X.509 attribute certificates
918 */
919 static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
920 {
921 bool first = TRUE;
922 time_t thisUpdate, nextUpdate, now = time(NULL);
923 enumerator_t *enumerator = list->create_enumerator(list);
924 certificate_t *cert;
925
926 while (enumerator->enumerate(enumerator, (void**)&cert))
927 {
928 ac_t *ac = (ac_t*)cert;
929 identification_t *id;
930 ietf_attributes_t *groups;
931 chunk_t chunk;
932
933 if (first)
934 {
935 fprintf(out, "\n");
936 fprintf(out, "List of X.509 Attribute Certificates:\n");
937 first = FALSE;
938 }
939 fprintf(out, "\n");
940
941 id = cert->get_subject(cert);
942 if (id)
943 {
944 fprintf(out, " holder: \"%Y\"\n", id);
945 }
946 id = ac->get_holderIssuer(ac);
947 if (id)
948 {
949 fprintf(out, " hissuer: \"%Y\"\n", id);
950 }
951 chunk = ac->get_holderSerial(ac);
952 if (chunk.ptr)
953 {
954 fprintf(out, " hserial: %#B\n", &chunk);
955 }
956 groups = ac->get_groups(ac);
957 if (groups)
958 {
959 fprintf(out, " groups: %s\n", groups->get_string(groups));
960 groups->destroy(groups);
961 }
962 fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
963 chunk = ac->get_serial(ac);
964 fprintf(out, " serial: %#B\n", &chunk);
965
966 /* list validity */
967 cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
968 fprintf(out, " updates: this %T\n", &thisUpdate, utc);
969 fprintf(out, " next %T, ", &nextUpdate, utc);
970 if (now > nextUpdate)
971 {
972 fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
973 }
974 else
975 {
976 fprintf(out, "ok");
977 if (now > nextUpdate - AC_WARNING_INTERVAL * 60 * 60 * 24)
978 {
979 fprintf(out, " (expires in %V)", &now, &nextUpdate);
980 }
981 fprintf(out, " \n");
982 }
983
984 /* list optional authorityKeyIdentifier */
985 chunk = ac->get_authKeyIdentifier(ac);
986 if (chunk.ptr)
987 {
988 fprintf(out, " authkey: %#B\n", &chunk);
989 }
990 }
991 enumerator->destroy(enumerator);
992 }
993
994 /**
995 * list all X.509 CRLs
996 */
997 static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
998 {
999 bool first = TRUE;
1000 time_t thisUpdate, nextUpdate, now = time(NULL);
1001 enumerator_t *enumerator = list->create_enumerator(list);
1002 certificate_t *cert;
1003
1004 while (enumerator->enumerate(enumerator, (void**)&cert))
1005 {
1006 crl_t *crl = (crl_t*)cert;
1007 chunk_t chunk;
1008
1009 if (first)
1010 {
1011 fprintf(out, "\n");
1012 fprintf(out, "List of X.509 CRLs:\n");
1013 first = FALSE;
1014 }
1015 fprintf(out, "\n");
1016
1017 fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
1018
1019 /* list optional crlNumber */
1020 chunk = crl->get_serial(crl);
1021 if (chunk.ptr)
1022 {
1023 fprintf(out, " serial: %#B\n", &chunk);
1024 }
1025 if (crl->is_delta_crl(crl, &chunk))
1026 {
1027 fprintf(out, " delta for: %#B\n", &chunk);
1028 }
1029
1030 /* count the number of revoked certificates */
1031 {
1032 int count = 0;
1033 enumerator_t *enumerator = crl->create_enumerator(crl);
1034
1035 while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
1036 {
1037 count++;
1038 }
1039 fprintf(out, " revoked: %d certificate%s\n", count,
1040 (count == 1)? "" : "s");
1041 enumerator->destroy(enumerator);
1042 }
1043
1044 /* list validity */
1045 cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
1046 fprintf(out, " updates: this %T\n", &thisUpdate, utc);
1047 fprintf(out, " next %T, ", &nextUpdate, utc);
1048 if (now > nextUpdate)
1049 {
1050 fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
1051 }
1052 else
1053 {
1054 fprintf(out, "ok");
1055 if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
1056 {
1057 fprintf(out, " (expires in %V)", &now, &nextUpdate);
1058 }
1059 fprintf(out, " \n");
1060 }
1061
1062 /* list optional authorityKeyIdentifier */
1063 chunk = crl->get_authKeyIdentifier(crl);
1064 if (chunk.ptr)
1065 {
1066 fprintf(out, " authkey: %#B\n", &chunk);
1067 }
1068 }
1069 enumerator->destroy(enumerator);
1070 }
1071
1072 /**
1073 * list all OCSP responses
1074 */
1075 static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out)
1076 {
1077 bool first = TRUE, ok;
1078 enumerator_t *enumerator = list->create_enumerator(list);
1079 certificate_t *cert;
1080 time_t produced, usable, now = time(NULL);
1081
1082 while (enumerator->enumerate(enumerator, (void**)&cert))
1083 {
1084 if (first)
1085 {
1086 fprintf(out, "\n");
1087 fprintf(out, "List of OCSP responses:\n");
1088 fprintf(out, "\n");
1089 first = FALSE;
1090 }
1091 fprintf(out, " signer: \"%Y\"\n", cert->get_issuer(cert));
1092
1093 /* check validity */
1094 ok = cert->get_validity(cert, &now, &produced, &usable);
1095 fprintf(out, " validity: produced at %T\n", &produced, utc);
1096 fprintf(out, " usable till %T, ", &usable, utc);
1097 if (ok)
1098 {
1099 fprintf(out, "ok\n");
1100 }
1101 else
1102 {
1103 fprintf(out, "expired (%V ago)\n", &now, &usable);
1104 }
1105 }
1106 enumerator->destroy(enumerator);
1107 }
1108
1109 /**
1110 * Print the name of an algorithm plus the name of the plugin that registered it
1111 */
1112 static void print_alg(FILE *out, int *len, enum_name_t *alg_names, int alg_type,
1113 const char *plugin_name)
1114 {
1115 char alg_name[BUF_LEN];
1116 int alg_name_len;
1117
1118 alg_name_len = sprintf(alg_name, " %N[%s]", alg_names, alg_type, plugin_name);
1119 if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE)
1120 {
1121 fprintf(out, "\n ");
1122 *len = 13;
1123 }
1124 fprintf(out, "%s", alg_name);
1125 *len += alg_name_len;
1126 }
1127
1128 /**
1129 * List of registered cryptographical algorithms
1130 */
1131 static void list_algs(FILE *out)
1132 {
1133 enumerator_t *enumerator;
1134 encryption_algorithm_t encryption;
1135 integrity_algorithm_t integrity;
1136 hash_algorithm_t hash;
1137 pseudo_random_function_t prf;
1138 diffie_hellman_group_t group;
1139 rng_quality_t quality;
1140 const char *plugin_name;
1141 int len;
1142
1143 fprintf(out, "\n");
1144 fprintf(out, "List of registered IKEv2 Algorithms:\n");
1145 fprintf(out, "\n encryption:");
1146 len = 13;
1147 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1148 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1149 {
1150 print_alg(out, &len, encryption_algorithm_names, encryption, plugin_name);
1151 }
1152 enumerator->destroy(enumerator);
1153 fprintf(out, "\n integrity: ");
1154 len = 13;
1155 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1156 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1157 {
1158 print_alg(out, &len, integrity_algorithm_names, integrity, plugin_name);
1159 }
1160 enumerator->destroy(enumerator);
1161 fprintf(out, "\n aead: ");
1162 len = 13;
1163 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
1164 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1165 {
1166 print_alg(out, &len, encryption_algorithm_names, encryption, plugin_name);
1167 }
1168 enumerator->destroy(enumerator);
1169 fprintf(out, "\n hasher: ");
1170 len = 13;
1171 enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
1172 while (enumerator->enumerate(enumerator, &hash, &plugin_name))
1173 {
1174 print_alg(out, &len, hash_algorithm_names, hash, plugin_name);
1175 }
1176 enumerator->destroy(enumerator);
1177 fprintf(out, "\n prf: ");
1178 len = 13;
1179 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1180 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1181 {
1182 print_alg(out, &len, pseudo_random_function_names, prf, plugin_name);
1183 }
1184 enumerator->destroy(enumerator);
1185 fprintf(out, "\n dh-group: ");
1186 len = 13;
1187 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1188 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1189 {
1190 print_alg(out, &len, diffie_hellman_group_names, group, plugin_name);
1191 }
1192 enumerator->destroy(enumerator);
1193 fprintf(out, "\n random-gen:");
1194 len = 13;
1195 enumerator = lib->crypto->create_rng_enumerator(lib->crypto);
1196 while (enumerator->enumerate(enumerator, &quality, &plugin_name))
1197 {
1198 print_alg(out, &len, rng_quality_names, quality, plugin_name);
1199 }
1200 enumerator->destroy(enumerator);
1201 fprintf(out, "\n");
1202 }
1203
1204 /**
1205 * List loaded plugin information
1206 */
1207 static void list_plugins(FILE *out)
1208 {
1209 plugin_feature_t *features, *fp;
1210 enumerator_t *enumerator;
1211 linked_list_t *list;
1212 plugin_t *plugin;
1213 int count, i;
1214 bool loaded;
1215 char *str;
1216
1217 fprintf(out, "\n");
1218 fprintf(out, "List of loaded Plugins:\n");
1219 fprintf(out, "\n");
1220
1221 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
1222 while (enumerator->enumerate(enumerator, &plugin, &list))
1223 {
1224 fprintf(out, "%s:\n", plugin->get_name(plugin));
1225 if (plugin->get_features)
1226 {
1227 count = plugin->get_features(plugin, &features);
1228 for (i = 0; i < count; i++)
1229 {
1230 str = plugin_feature_get_string(&features[i]);
1231 switch (features[i].kind)
1232 {
1233 case FEATURE_PROVIDE:
1234 fp = &features[i];
1235 loaded = list->find_first(list, NULL,
1236 (void**)&fp) == SUCCESS;
1237 fprintf(out, " %s%s\n",
1238 str, loaded ? "" : " (not loaded)");
1239 break;
1240 case FEATURE_DEPENDS:
1241 fprintf(out, " %s\n", str);
1242 break;
1243 case FEATURE_SDEPEND:
1244 fprintf(out, " %s(soft)\n", str);
1245 break;
1246 default:
1247 break;
1248 }
1249 free(str);
1250 }
1251 }
1252 }
1253 enumerator->destroy(enumerator);
1254 }
1255
1256 METHOD(stroke_list_t, list, void,
1257 private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
1258 {
1259 linked_list_t *cert_list = NULL;
1260
1261 if (msg->list.flags & LIST_PUBKEYS)
1262 {
1263 linked_list_t *pubkey_list = create_unique_cert_list(CERT_TRUSTED_PUBKEY);
1264
1265 stroke_list_pubkeys(pubkey_list, msg->list.utc, out);
1266 pubkey_list->destroy_offset(pubkey_list, offsetof(certificate_t, destroy));
1267 }
1268 if (msg->list.flags & LIST_CERTS)
1269 {
1270 linked_list_t *pgp_list = create_unique_cert_list(CERT_GPG);
1271
1272 stroke_list_pgp(pgp_list, msg->list.utc, out);
1273 pgp_list->destroy_offset(pgp_list, offsetof(certificate_t, destroy));
1274 }
1275 if (msg->list.flags & (LIST_CERTS | LIST_CACERTS | LIST_OCSPCERTS | LIST_AACERTS))
1276 {
1277 cert_list = create_unique_cert_list(CERT_X509);
1278 }
1279 if (msg->list.flags & LIST_CERTS)
1280 {
1281 stroke_list_certs(cert_list, "X.509 End Entity Certificates",
1282 X509_NONE, msg->list.utc, out);
1283 }
1284 if (msg->list.flags & LIST_CACERTS)
1285 {
1286 stroke_list_certs(cert_list, "X.509 CA Certificates",
1287 X509_CA, msg->list.utc, out);
1288 }
1289 if (msg->list.flags & LIST_OCSPCERTS)
1290 {
1291 stroke_list_certs(cert_list, "X.509 OCSP Signer Certificates",
1292 X509_OCSP_SIGNER, msg->list.utc, out);
1293 }
1294 if (msg->list.flags & LIST_AACERTS)
1295 {
1296 stroke_list_certs(cert_list, "X.509 AA Certificates",
1297 X509_AA, msg->list.utc, out);
1298 }
1299 DESTROY_OFFSET_IF(cert_list, offsetof(certificate_t, destroy));
1300
1301 if (msg->list.flags & LIST_ACERTS)
1302 {
1303 linked_list_t *ac_list = create_unique_cert_list(CERT_X509_AC);
1304
1305 stroke_list_acerts(ac_list, msg->list.utc, out);
1306 ac_list->destroy_offset(ac_list, offsetof(certificate_t, destroy));
1307 }
1308 if (msg->list.flags & LIST_CRLS)
1309 {
1310 linked_list_t *crl_list = create_unique_cert_list(CERT_X509_CRL);
1311
1312 stroke_list_crls(crl_list, msg->list.utc, out);
1313 crl_list->destroy_offset(crl_list, offsetof(certificate_t, destroy));
1314 }
1315 if (msg->list.flags & LIST_OCSP)
1316 {
1317 linked_list_t *ocsp_list = create_unique_cert_list(CERT_X509_OCSP_RESPONSE);
1318
1319 stroke_list_ocsp(ocsp_list, msg->list.utc, out);
1320
1321 ocsp_list->destroy_offset(ocsp_list, offsetof(certificate_t, destroy));
1322 }
1323 if (msg->list.flags & LIST_ALGS)
1324 {
1325 list_algs(out);
1326 }
1327 if (msg->list.flags & LIST_PLUGINS)
1328 {
1329 list_plugins(out);
1330 }
1331 }
1332
1333 /**
1334 * Print leases of a single pool
1335 */
1336 static void pool_leases(private_stroke_list_t *this, FILE *out, char *pool,
1337 host_t *address, u_int size, u_int online, u_int offline)
1338 {
1339 enumerator_t *enumerator;
1340 identification_t *id;
1341 host_t *lease;
1342 bool on;
1343 int found = 0;
1344
1345 fprintf(out, "Leases in pool '%s', usage: %u/%u, %u online\n",
1346 pool, online + offline, size, online);
1347 enumerator = this->attribute->create_lease_enumerator(this->attribute, pool);
1348 while (enumerator && enumerator->enumerate(enumerator, &id, &lease, &on))
1349 {
1350 if (!address || address->ip_equals(address, lease))
1351 {
1352 fprintf(out, " %15H %s '%Y'\n",
1353 lease, on ? "online" : "offline", id);
1354 found++;
1355 }
1356 }
1357 enumerator->destroy(enumerator);
1358 if (!found)
1359 {
1360 fprintf(out, " no matching leases found\n");
1361 }
1362 }
1363
1364 METHOD(stroke_list_t, leases, void,
1365 private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
1366 {
1367 enumerator_t *enumerator;
1368 u_int size, offline, online;
1369 host_t *address = NULL;
1370 char *pool;
1371 int found = 0;
1372
1373 if (msg->leases.address)
1374 {
1375 address = host_create_from_string(msg->leases.address, 0);
1376 }
1377
1378 enumerator = this->attribute->create_pool_enumerator(this->attribute);
1379 while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline))
1380 {
1381 if (!msg->leases.pool || streq(msg->leases.pool, pool))
1382 {
1383 pool_leases(this, out, pool, address, size, online, offline);
1384 found++;
1385 }
1386 }
1387 enumerator->destroy(enumerator);
1388 if (!found)
1389 {
1390 if (msg->leases.pool)
1391 {
1392 fprintf(out, "pool '%s' not found\n", msg->leases.pool);
1393 }
1394 else
1395 {
1396 fprintf(out, "no pools found\n");
1397 }
1398 }
1399 DESTROY_IF(address);
1400 }
1401
1402 METHOD(stroke_list_t, destroy, void,
1403 private_stroke_list_t *this)
1404 {
1405 free(this);
1406 }
1407
1408 /*
1409 * see header file
1410 */
1411 stroke_list_t *stroke_list_create(stroke_attribute_t *attribute)
1412 {
1413 private_stroke_list_t *this;
1414
1415 INIT(this,
1416 .public = {
1417
1418 .list = _list,
1419 .status = _status,
1420 .leases = _leases,
1421 .destroy = _destroy,
1422 },
1423 .uptime = time_monotonic(NULL),
1424 .attribute = attribute,
1425 );
1426
1427 return &this->public;
1428 }
1429