Added a listplugins stroke command to show plugin features
[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;
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 fprintf(out, " loaded plugins: ");
453 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
454 while (enumerator->enumerate(enumerator, &plugin, NULL))
455 {
456 fprintf(out, "%s ", plugin->get_name(plugin));
457 }
458 enumerator->destroy(enumerator);
459 fprintf(out, "\n");
460
461 first = TRUE;
462 enumerator = this->attribute->create_pool_enumerator(this->attribute);
463 while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline))
464 {
465 if (name && !streq(name, pool))
466 {
467 continue;
468 }
469 if (first)
470 {
471 first = FALSE;
472 fprintf(out, "Virtual IP pools (size/online/offline):\n");
473 }
474 fprintf(out, " %s: %u/%u/%u\n", pool, size, online, offline);
475 }
476 enumerator->destroy(enumerator);
477
478 enumerator = hydra->kernel_interface->create_address_enumerator(
479 hydra->kernel_interface, FALSE, FALSE);
480 fprintf(out, "Listening IP addresses:\n");
481 while (enumerator->enumerate(enumerator, (void**)&host))
482 {
483 fprintf(out, " %H\n", host);
484 }
485 enumerator->destroy(enumerator);
486
487 fprintf(out, "Connections:\n");
488 enumerator = charon->backends->create_peer_cfg_enumerator(
489 charon->backends, NULL, NULL, NULL, NULL);
490 while (enumerator->enumerate(enumerator, &peer_cfg))
491 {
492 if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
493 (name && !streq(name, peer_cfg->get_name(peer_cfg))))
494 {
495 continue;
496 }
497
498 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
499 fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg),
500 ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg));
501
502 dpd = peer_cfg->get_dpd(peer_cfg);
503 if (dpd)
504 {
505 fprintf(out, ", dpddelay=%us", dpd);
506 }
507 fprintf(out, "\n");
508
509 log_auth_cfgs(out, peer_cfg, TRUE);
510 log_auth_cfgs(out, peer_cfg, FALSE);
511
512 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
513 while (children->enumerate(children, &child_cfg))
514 {
515 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
516 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
517 fprintf(out, "%12s: child: %#R=== %#R%N",
518 child_cfg->get_name(child_cfg), my_ts, other_ts,
519 ipsec_mode_names, child_cfg->get_mode(child_cfg));
520 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
521 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
522
523 if (dpd)
524 {
525 fprintf(out, ", dpdaction=%N", action_names,
526 child_cfg->get_dpd_action(child_cfg));
527 }
528 fprintf(out, "\n");
529 }
530 children->destroy(children);
531 }
532 enumerator->destroy(enumerator);
533 }
534
535 /* Enumerate shunt policies */
536 first = TRUE;
537 enumerator = charon->shunts->create_enumerator(charon->shunts);
538 while (enumerator->enumerate(enumerator, &child_cfg))
539 {
540 if (name && !streq(name, child_cfg->get_name(child_cfg)))
541 {
542 continue;
543 }
544 if (first)
545 {
546 fprintf(out, "Shunted Connections:\n");
547 first = FALSE;
548 }
549 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
550 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
551 fprintf(out, "%12s: %#R=== %#R%N\n",
552 child_cfg->get_name(child_cfg), my_ts, other_ts,
553 ipsec_mode_names, child_cfg->get_mode(child_cfg));
554 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
555 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
556 }
557 enumerator->destroy(enumerator);
558
559 /* Enumerate traps */
560 first = TRUE;
561 enumerator = charon->traps->create_enumerator(charon->traps);
562 while (enumerator->enumerate(enumerator, NULL, &child_sa))
563 {
564 if (name && !streq(name, child_sa->get_name(child_sa)))
565 {
566 continue;
567 }
568 if (first)
569 {
570 fprintf(out, "Routed Connections:\n");
571 first = FALSE;
572 }
573 log_child_sa(out, child_sa, all);
574 }
575 enumerator->destroy(enumerator);
576
577 half_open = charon->ike_sa_manager->get_half_open_count(
578 charon->ike_sa_manager, NULL);
579 fprintf(out, "Security Associations (%u up, %u connecting):\n",
580 charon->ike_sa_manager->get_count(charon->ike_sa_manager) - half_open,
581 half_open);
582 enumerator = charon->controller->create_ike_sa_enumerator(
583 charon->controller, wait);
584 while (enumerator->enumerate(enumerator, &ike_sa))
585 {
586 bool ike_printed = FALSE;
587 enumerator_t *children = ike_sa->create_child_sa_enumerator(ike_sa);
588
589 if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
590 {
591 log_ike_sa(out, ike_sa, all);
592 found = TRUE;
593 ike_printed = TRUE;
594 }
595
596 while (children->enumerate(children, (void**)&child_sa))
597 {
598 if (name == NULL || streq(name, child_sa->get_name(child_sa)))
599 {
600 if (!ike_printed)
601 {
602 log_ike_sa(out, ike_sa, all);
603 found = TRUE;
604 ike_printed = TRUE;
605 }
606 log_child_sa(out, child_sa, all);
607 }
608 }
609 children->destroy(children);
610 }
611 enumerator->destroy(enumerator);
612
613 if (!found)
614 {
615 if (name)
616 {
617 fprintf(out, " no match\n");
618 }
619 else
620 {
621 fprintf(out, " none\n");
622 }
623 }
624 }
625
626 /**
627 * create a unique certificate list without duplicates
628 * certicates having the same issuer are grouped together.
629 */
630 static linked_list_t* create_unique_cert_list(certificate_type_t type)
631 {
632 linked_list_t *list = linked_list_create();
633 enumerator_t *enumerator = lib->credmgr->create_cert_enumerator(
634 lib->credmgr, type, KEY_ANY, NULL, FALSE);
635 certificate_t *cert;
636
637 while (enumerator->enumerate(enumerator, (void**)&cert))
638 {
639 enumerator_t *added = list->create_enumerator(list);
640 identification_t *issuer = cert->get_issuer(cert);
641 bool previous_same, same = FALSE, found = FALSE;
642 certificate_t *list_cert;
643
644 while (added->enumerate(added, (void**)&list_cert))
645 {
646 if (list_cert->equals(list_cert, cert))
647 { /* stop if we found a duplicate*/
648 found = TRUE;
649 break;
650 }
651 previous_same = same;
652 same = list_cert->has_issuer(list_cert, issuer);
653 if (previous_same && !same)
654 { /* group certificates with same issuer */
655 break;
656 }
657 }
658 if (!found)
659 {
660 list->insert_before(list, added, cert->get_ref(cert));
661 }
662 added->destroy(added);
663 }
664 enumerator->destroy(enumerator);
665 return list;
666 }
667
668 /**
669 * Print a single public key.
670 */
671 static void list_public_key(public_key_t *public, FILE *out)
672 {
673 private_key_t *private = NULL;
674 chunk_t keyid;
675 identification_t *id;
676 auth_cfg_t *auth;
677
678 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
679 {
680 id = identification_create_from_encoding(ID_KEY_ID, keyid);
681 auth = auth_cfg_create();
682 private = lib->credmgr->get_private(lib->credmgr,
683 public->get_type(public), id, auth);
684 auth->destroy(auth);
685 id->destroy(id);
686 }
687
688 fprintf(out, " pubkey: %N %d bits%s\n",
689 key_type_names, public->get_type(public),
690 public->get_keysize(public),
691 private ? ", has private key" : "");
692 if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
693 {
694 fprintf(out, " keyid: %#B\n", &keyid);
695 }
696 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
697 {
698 fprintf(out, " subjkey: %#B\n", &keyid);
699 }
700 DESTROY_IF(private);
701 }
702
703 /**
704 * list all raw public keys
705 */
706 static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out)
707 {
708 bool first = TRUE;
709
710 enumerator_t *enumerator = list->create_enumerator(list);
711 certificate_t *cert;
712
713 while (enumerator->enumerate(enumerator, (void**)&cert))
714 {
715 public_key_t *public = cert->get_public_key(cert);
716
717 if (public)
718 {
719 if (first)
720 {
721 fprintf(out, "\n");
722 fprintf(out, "List of Raw Public Keys:\n");
723 first = FALSE;
724 }
725 fprintf(out, "\n");
726
727 list_public_key(public, out);
728 public->destroy(public);
729 }
730 }
731 enumerator->destroy(enumerator);
732 }
733
734 /**
735 * list OpenPGP certificates
736 */
737 static void stroke_list_pgp(linked_list_t *list,bool utc, FILE *out)
738 {
739 bool first = TRUE;
740 time_t now = time(NULL);
741 enumerator_t *enumerator = list->create_enumerator(list);
742 certificate_t *cert;
743
744 while (enumerator->enumerate(enumerator, (void**)&cert))
745 {
746 time_t created, until;
747 public_key_t *public;
748 pgp_certificate_t *pgp_cert = (pgp_certificate_t*)cert;
749 chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert);
750
751 if (first)
752 {
753
754 fprintf(out, "\n");
755 fprintf(out, "List of PGP End Entity Certificates:\n");
756 first = FALSE;
757 }
758 fprintf(out, "\n");
759 fprintf(out, " userid: '%Y'\n", cert->get_subject(cert));
760
761 fprintf(out, " digest: %#B\n", &fingerprint);
762
763 /* list validity */
764 cert->get_validity(cert, &now, &created, &until);
765 fprintf(out, " created: %T\n", &created, utc);
766 fprintf(out, " until: %T%s\n", &until, utc,
767 (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":"");
768
769 public = cert->get_public_key(cert);
770 if (public)
771 {
772 list_public_key(public, out);
773 public->destroy(public);
774 }
775 }
776 enumerator->destroy(enumerator);
777 }
778
779 /**
780 * list all X.509 certificates matching the flags
781 */
782 static void stroke_list_certs(linked_list_t *list, char *label,
783 x509_flag_t flags, bool utc, FILE *out)
784 {
785 bool first = TRUE;
786 time_t now = time(NULL);
787 enumerator_t *enumerator;
788 certificate_t *cert;
789 x509_flag_t flag_mask;
790
791 /* mask all auxiliary flags */
792 flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH |
793 X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS );
794
795 enumerator = list->create_enumerator(list);
796 while (enumerator->enumerate(enumerator, (void**)&cert))
797 {
798 x509_t *x509 = (x509_t*)cert;
799 x509_flag_t x509_flags = x509->get_flags(x509) & flag_mask;
800
801 /* list only if flag is set or flag == 0 */
802 if ((x509_flags & flags) || (x509_flags == flags))
803 {
804 enumerator_t *enumerator;
805 identification_t *altName;
806 bool first_altName = TRUE;
807 u_int pathlen;
808 chunk_t serial, authkey;
809 time_t notBefore, notAfter;
810 public_key_t *public;
811
812 if (first)
813 {
814 fprintf(out, "\n");
815 fprintf(out, "List of %s:\n", label);
816 first = FALSE;
817 }
818 fprintf(out, "\n");
819
820 /* list subjectAltNames */
821 enumerator = x509->create_subjectAltName_enumerator(x509);
822 while (enumerator->enumerate(enumerator, (void**)&altName))
823 {
824 if (first_altName)
825 {
826 fprintf(out, " altNames: ");
827 first_altName = FALSE;
828 }
829 else
830 {
831 fprintf(out, ", ");
832 }
833 fprintf(out, "%Y", altName);
834 }
835 if (!first_altName)
836 {
837 fprintf(out, "\n");
838 }
839 enumerator->destroy(enumerator);
840
841 fprintf(out, " subject: \"%Y\"\n", cert->get_subject(cert));
842 fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
843 serial = x509->get_serial(x509);
844 fprintf(out, " serial: %#B\n", &serial);
845
846 /* list validity */
847 cert->get_validity(cert, &now, &notBefore, &notAfter);
848 fprintf(out, " validity: not before %T, ", &notBefore, utc);
849 if (now < notBefore)
850 {
851 fprintf(out, "not valid yet (valid in %V)\n", &now, &notBefore);
852 }
853 else
854 {
855 fprintf(out, "ok\n");
856 }
857 fprintf(out, " not after %T, ", &notAfter, utc);
858 if (now > notAfter)
859 {
860 fprintf(out, "expired (%V ago)\n", &now, &notAfter);
861 }
862 else
863 {
864 fprintf(out, "ok");
865 if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
866 {
867 fprintf(out, " (expires in %V)", &now, &notAfter);
868 }
869 fprintf(out, " \n");
870 }
871
872 public = cert->get_public_key(cert);
873 if (public)
874 {
875 list_public_key(public, out);
876 public->destroy(public);
877 }
878
879 /* list optional authorityKeyIdentifier */
880 authkey = x509->get_authKeyIdentifier(x509);
881 if (authkey.ptr)
882 {
883 fprintf(out, " authkey: %#B\n", &authkey);
884 }
885
886 /* list optional pathLenConstraint */
887 pathlen = x509->get_constraint(x509, X509_PATH_LEN);
888 if (pathlen != X509_NO_CONSTRAINT)
889 {
890 fprintf(out, " pathlen: %u\n", pathlen);
891 }
892
893 /* list optional ipAddrBlocks */
894 if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS)
895 {
896 traffic_selector_t *ipAddrBlock;
897 bool first_ipAddrBlock = TRUE;
898
899 fprintf(out, " addresses: ");
900 enumerator = x509->create_ipAddrBlock_enumerator(x509);
901 while (enumerator->enumerate(enumerator, &ipAddrBlock))
902 {
903 if (first_ipAddrBlock)
904 {
905 first_ipAddrBlock = FALSE;
906 }
907 else
908 {
909 fprintf(out, ", ");
910 }
911 fprintf(out, "%R", ipAddrBlock);
912 }
913 enumerator->destroy(enumerator);
914 fprintf(out, "\n");
915 }
916 }
917 }
918 enumerator->destroy(enumerator);
919 }
920
921 /**
922 * list all X.509 attribute certificates
923 */
924 static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
925 {
926 bool first = TRUE;
927 time_t thisUpdate, nextUpdate, now = time(NULL);
928 enumerator_t *enumerator = list->create_enumerator(list);
929 certificate_t *cert;
930
931 while (enumerator->enumerate(enumerator, (void**)&cert))
932 {
933 ac_t *ac = (ac_t*)cert;
934 identification_t *id;
935 ietf_attributes_t *groups;
936 chunk_t chunk;
937
938 if (first)
939 {
940 fprintf(out, "\n");
941 fprintf(out, "List of X.509 Attribute Certificates:\n");
942 first = FALSE;
943 }
944 fprintf(out, "\n");
945
946 id = cert->get_subject(cert);
947 if (id)
948 {
949 fprintf(out, " holder: \"%Y\"\n", id);
950 }
951 id = ac->get_holderIssuer(ac);
952 if (id)
953 {
954 fprintf(out, " hissuer: \"%Y\"\n", id);
955 }
956 chunk = ac->get_holderSerial(ac);
957 if (chunk.ptr)
958 {
959 fprintf(out, " hserial: %#B\n", &chunk);
960 }
961 groups = ac->get_groups(ac);
962 if (groups)
963 {
964 fprintf(out, " groups: %s\n", groups->get_string(groups));
965 groups->destroy(groups);
966 }
967 fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
968 chunk = ac->get_serial(ac);
969 fprintf(out, " serial: %#B\n", &chunk);
970
971 /* list validity */
972 cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
973 fprintf(out, " updates: this %T\n", &thisUpdate, utc);
974 fprintf(out, " next %T, ", &nextUpdate, utc);
975 if (now > nextUpdate)
976 {
977 fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
978 }
979 else
980 {
981 fprintf(out, "ok");
982 if (now > nextUpdate - AC_WARNING_INTERVAL * 60 * 60 * 24)
983 {
984 fprintf(out, " (expires in %V)", &now, &nextUpdate);
985 }
986 fprintf(out, " \n");
987 }
988
989 /* list optional authorityKeyIdentifier */
990 chunk = ac->get_authKeyIdentifier(ac);
991 if (chunk.ptr)
992 {
993 fprintf(out, " authkey: %#B\n", &chunk);
994 }
995 }
996 enumerator->destroy(enumerator);
997 }
998
999 /**
1000 * list all X.509 CRLs
1001 */
1002 static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
1003 {
1004 bool first = TRUE;
1005 time_t thisUpdate, nextUpdate, now = time(NULL);
1006 enumerator_t *enumerator = list->create_enumerator(list);
1007 certificate_t *cert;
1008
1009 while (enumerator->enumerate(enumerator, (void**)&cert))
1010 {
1011 crl_t *crl = (crl_t*)cert;
1012 chunk_t chunk;
1013
1014 if (first)
1015 {
1016 fprintf(out, "\n");
1017 fprintf(out, "List of X.509 CRLs:\n");
1018 first = FALSE;
1019 }
1020 fprintf(out, "\n");
1021
1022 fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
1023
1024 /* list optional crlNumber */
1025 chunk = crl->get_serial(crl);
1026 if (chunk.ptr)
1027 {
1028 fprintf(out, " serial: %#B\n", &chunk);
1029 }
1030 if (crl->is_delta_crl(crl, &chunk))
1031 {
1032 fprintf(out, " delta for: %#B\n", &chunk);
1033 }
1034
1035 /* count the number of revoked certificates */
1036 {
1037 int count = 0;
1038 enumerator_t *enumerator = crl->create_enumerator(crl);
1039
1040 while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
1041 {
1042 count++;
1043 }
1044 fprintf(out, " revoked: %d certificate%s\n", count,
1045 (count == 1)? "" : "s");
1046 enumerator->destroy(enumerator);
1047 }
1048
1049 /* list validity */
1050 cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
1051 fprintf(out, " updates: this %T\n", &thisUpdate, utc);
1052 fprintf(out, " next %T, ", &nextUpdate, utc);
1053 if (now > nextUpdate)
1054 {
1055 fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
1056 }
1057 else
1058 {
1059 fprintf(out, "ok");
1060 if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
1061 {
1062 fprintf(out, " (expires in %V)", &now, &nextUpdate);
1063 }
1064 fprintf(out, " \n");
1065 }
1066
1067 /* list optional authorityKeyIdentifier */
1068 chunk = crl->get_authKeyIdentifier(crl);
1069 if (chunk.ptr)
1070 {
1071 fprintf(out, " authkey: %#B\n", &chunk);
1072 }
1073 }
1074 enumerator->destroy(enumerator);
1075 }
1076
1077 /**
1078 * list all OCSP responses
1079 */
1080 static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out)
1081 {
1082 bool first = TRUE, ok;
1083 enumerator_t *enumerator = list->create_enumerator(list);
1084 certificate_t *cert;
1085 time_t produced, usable, now = time(NULL);
1086
1087 while (enumerator->enumerate(enumerator, (void**)&cert))
1088 {
1089 if (first)
1090 {
1091 fprintf(out, "\n");
1092 fprintf(out, "List of OCSP responses:\n");
1093 fprintf(out, "\n");
1094 first = FALSE;
1095 }
1096 fprintf(out, " signer: \"%Y\"\n", cert->get_issuer(cert));
1097
1098 /* check validity */
1099 ok = cert->get_validity(cert, &now, &produced, &usable);
1100 fprintf(out, " validity: produced at %T\n", &produced, utc);
1101 fprintf(out, " usable till %T, ", &usable, utc);
1102 if (ok)
1103 {
1104 fprintf(out, "ok\n");
1105 }
1106 else
1107 {
1108 fprintf(out, "expired (%V ago)\n", &now, &usable);
1109 }
1110 }
1111 enumerator->destroy(enumerator);
1112 }
1113
1114 /**
1115 * Print the name of an algorithm plus the name of the plugin that registered it
1116 */
1117 static void print_alg(FILE *out, int *len, enum_name_t *alg_names, int alg_type,
1118 const char *plugin_name)
1119 {
1120 char alg_name[BUF_LEN];
1121 int alg_name_len;
1122
1123 alg_name_len = sprintf(alg_name, " %N[%s]", alg_names, alg_type, plugin_name);
1124 if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE)
1125 {
1126 fprintf(out, "\n ");
1127 *len = 13;
1128 }
1129 fprintf(out, "%s", alg_name);
1130 *len += alg_name_len;
1131 }
1132
1133 /**
1134 * List of registered cryptographical algorithms
1135 */
1136 static void list_algs(FILE *out)
1137 {
1138 enumerator_t *enumerator;
1139 encryption_algorithm_t encryption;
1140 integrity_algorithm_t integrity;
1141 hash_algorithm_t hash;
1142 pseudo_random_function_t prf;
1143 diffie_hellman_group_t group;
1144 rng_quality_t quality;
1145 const char *plugin_name;
1146 int len;
1147
1148 fprintf(out, "\n");
1149 fprintf(out, "List of registered IKEv2 Algorithms:\n");
1150 fprintf(out, "\n encryption:");
1151 len = 13;
1152 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1153 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1154 {
1155 print_alg(out, &len, encryption_algorithm_names, encryption, plugin_name);
1156 }
1157 enumerator->destroy(enumerator);
1158 fprintf(out, "\n integrity: ");
1159 len = 13;
1160 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1161 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1162 {
1163 print_alg(out, &len, integrity_algorithm_names, integrity, plugin_name);
1164 }
1165 enumerator->destroy(enumerator);
1166 fprintf(out, "\n aead: ");
1167 len = 13;
1168 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
1169 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1170 {
1171 print_alg(out, &len, encryption_algorithm_names, encryption, plugin_name);
1172 }
1173 enumerator->destroy(enumerator);
1174 fprintf(out, "\n hasher: ");
1175 len = 13;
1176 enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
1177 while (enumerator->enumerate(enumerator, &hash, &plugin_name))
1178 {
1179 print_alg(out, &len, hash_algorithm_names, hash, plugin_name);
1180 }
1181 enumerator->destroy(enumerator);
1182 fprintf(out, "\n prf: ");
1183 len = 13;
1184 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1185 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1186 {
1187 print_alg(out, &len, pseudo_random_function_names, prf, plugin_name);
1188 }
1189 enumerator->destroy(enumerator);
1190 fprintf(out, "\n dh-group: ");
1191 len = 13;
1192 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1193 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1194 {
1195 print_alg(out, &len, diffie_hellman_group_names, group, plugin_name);
1196 }
1197 enumerator->destroy(enumerator);
1198 fprintf(out, "\n random-gen:");
1199 len = 13;
1200 enumerator = lib->crypto->create_rng_enumerator(lib->crypto);
1201 while (enumerator->enumerate(enumerator, &quality, &plugin_name))
1202 {
1203 print_alg(out, &len, rng_quality_names, quality, plugin_name);
1204 }
1205 enumerator->destroy(enumerator);
1206 fprintf(out, "\n");
1207 }
1208
1209 /**
1210 * List loaded plugin information
1211 */
1212 static void list_plugins(FILE *out)
1213 {
1214 plugin_feature_t *features, *fp;
1215 enumerator_t *enumerator;
1216 linked_list_t *list;
1217 plugin_t *plugin;
1218 int count, i;
1219 bool loaded;
1220 char *str;
1221
1222 fprintf(out, "\n");
1223 fprintf(out, "List of loaded plugins:\n");
1224
1225 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
1226 while (enumerator->enumerate(enumerator, &plugin, &list))
1227 {
1228 fprintf(out, "%s:\n", plugin->get_name(plugin));
1229 if (plugin->get_features)
1230 {
1231 count = plugin->get_features(plugin, &features);
1232 for (i = 0; i < count; i++)
1233 {
1234 str = plugin_feature_get_string(&features[i]);
1235 switch (features[i].kind)
1236 {
1237 case FEATURE_PROVIDE:
1238 fp = &features[i];
1239 loaded = list->find_first(list, NULL,
1240 (void**)&fp) == SUCCESS;
1241 fprintf(out, " %s%s\n",
1242 str, loaded ? "" : " (not loaded)");
1243 break;
1244 case FEATURE_DEPENDS:
1245 fprintf(out, " %s\n", str);
1246 break;
1247 case FEATURE_SDEPEND:
1248 fprintf(out, " %s(soft)\n", str);
1249 break;
1250 default:
1251 break;
1252 }
1253 free(str);
1254 }
1255 }
1256 }
1257 enumerator->destroy(enumerator);
1258 }
1259
1260 METHOD(stroke_list_t, list, void,
1261 private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
1262 {
1263 linked_list_t *cert_list = NULL;
1264
1265 if (msg->list.flags & LIST_PUBKEYS)
1266 {
1267 linked_list_t *pubkey_list = create_unique_cert_list(CERT_TRUSTED_PUBKEY);
1268
1269 stroke_list_pubkeys(pubkey_list, msg->list.utc, out);
1270 pubkey_list->destroy_offset(pubkey_list, offsetof(certificate_t, destroy));
1271 }
1272 if (msg->list.flags & LIST_CERTS)
1273 {
1274 linked_list_t *pgp_list = create_unique_cert_list(CERT_GPG);
1275
1276 stroke_list_pgp(pgp_list, msg->list.utc, out);
1277 pgp_list->destroy_offset(pgp_list, offsetof(certificate_t, destroy));
1278 }
1279 if (msg->list.flags & (LIST_CERTS | LIST_CACERTS | LIST_OCSPCERTS | LIST_AACERTS))
1280 {
1281 cert_list = create_unique_cert_list(CERT_X509);
1282 }
1283 if (msg->list.flags & LIST_CERTS)
1284 {
1285 stroke_list_certs(cert_list, "X.509 End Entity Certificates",
1286 X509_NONE, msg->list.utc, out);
1287 }
1288 if (msg->list.flags & LIST_CACERTS)
1289 {
1290 stroke_list_certs(cert_list, "X.509 CA Certificates",
1291 X509_CA, msg->list.utc, out);
1292 }
1293 if (msg->list.flags & LIST_OCSPCERTS)
1294 {
1295 stroke_list_certs(cert_list, "X.509 OCSP Signer Certificates",
1296 X509_OCSP_SIGNER, msg->list.utc, out);
1297 }
1298 if (msg->list.flags & LIST_AACERTS)
1299 {
1300 stroke_list_certs(cert_list, "X.509 AA Certificates",
1301 X509_AA, msg->list.utc, out);
1302 }
1303 DESTROY_OFFSET_IF(cert_list, offsetof(certificate_t, destroy));
1304
1305 if (msg->list.flags & LIST_ACERTS)
1306 {
1307 linked_list_t *ac_list = create_unique_cert_list(CERT_X509_AC);
1308
1309 stroke_list_acerts(ac_list, msg->list.utc, out);
1310 ac_list->destroy_offset(ac_list, offsetof(certificate_t, destroy));
1311 }
1312 if (msg->list.flags & LIST_CRLS)
1313 {
1314 linked_list_t *crl_list = create_unique_cert_list(CERT_X509_CRL);
1315
1316 stroke_list_crls(crl_list, msg->list.utc, out);
1317 crl_list->destroy_offset(crl_list, offsetof(certificate_t, destroy));
1318 }
1319 if (msg->list.flags & LIST_OCSP)
1320 {
1321 linked_list_t *ocsp_list = create_unique_cert_list(CERT_X509_OCSP_RESPONSE);
1322
1323 stroke_list_ocsp(ocsp_list, msg->list.utc, out);
1324
1325 ocsp_list->destroy_offset(ocsp_list, offsetof(certificate_t, destroy));
1326 }
1327 if (msg->list.flags & LIST_ALGS)
1328 {
1329 list_algs(out);
1330 }
1331 if (msg->list.flags & LIST_PLUGINS)
1332 {
1333 list_plugins(out);
1334 }
1335 }
1336
1337 /**
1338 * Print leases of a single pool
1339 */
1340 static void pool_leases(private_stroke_list_t *this, FILE *out, char *pool,
1341 host_t *address, u_int size, u_int online, u_int offline)
1342 {
1343 enumerator_t *enumerator;
1344 identification_t *id;
1345 host_t *lease;
1346 bool on;
1347 int found = 0;
1348
1349 fprintf(out, "Leases in pool '%s', usage: %u/%u, %u online\n",
1350 pool, online + offline, size, online);
1351 enumerator = this->attribute->create_lease_enumerator(this->attribute, pool);
1352 while (enumerator && enumerator->enumerate(enumerator, &id, &lease, &on))
1353 {
1354 if (!address || address->ip_equals(address, lease))
1355 {
1356 fprintf(out, " %15H %s '%Y'\n",
1357 lease, on ? "online" : "offline", id);
1358 found++;
1359 }
1360 }
1361 enumerator->destroy(enumerator);
1362 if (!found)
1363 {
1364 fprintf(out, " no matching leases found\n");
1365 }
1366 }
1367
1368 METHOD(stroke_list_t, leases, void,
1369 private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
1370 {
1371 enumerator_t *enumerator;
1372 u_int size, offline, online;
1373 host_t *address = NULL;
1374 char *pool;
1375 int found = 0;
1376
1377 if (msg->leases.address)
1378 {
1379 address = host_create_from_string(msg->leases.address, 0);
1380 }
1381
1382 enumerator = this->attribute->create_pool_enumerator(this->attribute);
1383 while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline))
1384 {
1385 if (!msg->leases.pool || streq(msg->leases.pool, pool))
1386 {
1387 pool_leases(this, out, pool, address, size, online, offline);
1388 found++;
1389 }
1390 }
1391 enumerator->destroy(enumerator);
1392 if (!found)
1393 {
1394 if (msg->leases.pool)
1395 {
1396 fprintf(out, "pool '%s' not found\n", msg->leases.pool);
1397 }
1398 else
1399 {
1400 fprintf(out, "no pools found\n");
1401 }
1402 }
1403 DESTROY_IF(address);
1404 }
1405
1406 METHOD(stroke_list_t, destroy, void,
1407 private_stroke_list_t *this)
1408 {
1409 free(this);
1410 }
1411
1412 /*
1413 * see header file
1414 */
1415 stroke_list_t *stroke_list_create(stroke_attribute_t *attribute)
1416 {
1417 private_stroke_list_t *this;
1418
1419 INIT(this,
1420 .public = {
1421
1422 .list = _list,
1423 .status = _status,
1424 .leases = _leases,
1425 .destroy = _destroy,
1426 },
1427 .uptime = time_monotonic(NULL),
1428 .attribute = attribute,
1429 );
1430
1431 return &this->public;
1432 }
1433