Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_authority.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2016-2019 Tobias Brunner
! 3: * Copyright (C) 2015 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #define _GNU_SOURCE
! 18:
! 19: #include "vici_authority.h"
! 20: #include "vici_builder.h"
! 21:
! 22: #include <threading/rwlock.h>
! 23: #include <collections/linked_list.h>
! 24: #include <credentials/certificates/x509.h>
! 25: #include <utils/debug.h>
! 26:
! 27: #include <stdio.h>
! 28:
! 29: typedef struct private_vici_authority_t private_vici_authority_t;
! 30:
! 31: /**
! 32: * Private data of an vici_authority_t object.
! 33: */
! 34: struct private_vici_authority_t {
! 35:
! 36: /**
! 37: * Public vici_authority_t interface.
! 38: */
! 39: vici_authority_t public;
! 40:
! 41: /**
! 42: * Dispatcher
! 43: */
! 44: vici_dispatcher_t *dispatcher;
! 45:
! 46: /**
! 47: * credential backend managed by VICI used for our ca certificates
! 48: */
! 49: vici_cred_t *cred;
! 50:
! 51: /**
! 52: * List of certification authorities
! 53: */
! 54: linked_list_t *authorities;
! 55:
! 56: /**
! 57: * rwlock to lock access to certification authorities
! 58: */
! 59: rwlock_t *lock;
! 60:
! 61: };
! 62:
! 63: typedef struct authority_t authority_t;
! 64:
! 65: /**
! 66: * loaded certification authorities
! 67: */
! 68: struct authority_t {
! 69:
! 70: /**
! 71: * Name of the certification authority
! 72: */
! 73: char *name;
! 74:
! 75: /**
! 76: * Reference to CA certificate
! 77: */
! 78: certificate_t *cert;
! 79:
! 80: /**
! 81: * CRL URIs
! 82: */
! 83: linked_list_t *crl_uris;
! 84:
! 85: /**
! 86: * OCSP URIs
! 87: */
! 88: linked_list_t *ocsp_uris;
! 89:
! 90: /**
! 91: * Base URI used for certificates from this CA
! 92: */
! 93: char *cert_uri_base;
! 94: };
! 95:
! 96: /**
! 97: * create a new certification authority
! 98: */
! 99: static authority_t *authority_create(char *name)
! 100: {
! 101: authority_t *authority;
! 102:
! 103: INIT(authority,
! 104: .name = strdup(name),
! 105: .crl_uris = linked_list_create(),
! 106: .ocsp_uris = linked_list_create(),
! 107: );
! 108:
! 109: return authority;
! 110: }
! 111:
! 112: /**
! 113: * destroy a certification authority
! 114: */
! 115: static void authority_destroy(authority_t *this)
! 116: {
! 117: this->crl_uris->destroy_function(this->crl_uris, free);
! 118: this->ocsp_uris->destroy_function(this->ocsp_uris, free);
! 119: DESTROY_IF(this->cert);
! 120: free(this->cert_uri_base);
! 121: free(this->name);
! 122: free(this);
! 123: }
! 124:
! 125:
! 126: /**
! 127: * Create a (error) reply message
! 128: */
! 129: static vici_message_t* create_reply(char *fmt, ...)
! 130: {
! 131: vici_builder_t *builder;
! 132: va_list args;
! 133:
! 134: builder = vici_builder_create();
! 135: builder->add_kv(builder, "success", fmt ? "no" : "yes");
! 136: if (fmt)
! 137: {
! 138: va_start(args, fmt);
! 139: builder->vadd_kv(builder, "errmsg", fmt, args);
! 140: va_end(args);
! 141: }
! 142: return builder->finalize(builder);
! 143: }
! 144:
! 145: /**
! 146: * A rule to parse a key/value or list item
! 147: */
! 148: typedef struct {
! 149: /** name of the key/value or list */
! 150: char *name;
! 151: /** function to parse value */
! 152: bool (*parse)(void *out, chunk_t value);
! 153: /** result, passed to parse() */
! 154: void *out;
! 155: } parse_rule_t;
! 156:
! 157: /**
! 158: * Parse key/values using a rule-set
! 159: */
! 160: static bool parse_rules(parse_rule_t *rules, int count, char *name,
! 161: chunk_t value, vici_message_t **reply)
! 162: {
! 163: int i;
! 164:
! 165: for (i = 0; i < count; i++)
! 166: {
! 167: if (streq(name, rules[i].name))
! 168: {
! 169: if (rules[i].parse(rules[i].out, value))
! 170: {
! 171: return TRUE;
! 172: }
! 173: *reply = create_reply("invalid value for: %s, authority discarded",
! 174: name);
! 175: return FALSE;
! 176: }
! 177: }
! 178: *reply = create_reply("unknown option: %s, authority discarded", name);
! 179: return FALSE;
! 180: }
! 181:
! 182: /**
! 183: * Parse callback data, passed to each callback
! 184: */
! 185: typedef struct {
! 186: private_vici_authority_t *this;
! 187: vici_message_t *reply;
! 188: } request_data_t;
! 189:
! 190: /**
! 191: * Data associated with an authority load
! 192: */
! 193: typedef struct {
! 194: request_data_t *request;
! 195: authority_t *authority;
! 196: char *handle;
! 197: uint32_t slot;
! 198: char *module;
! 199: char *file;
! 200: } load_data_t;
! 201:
! 202: /**
! 203: * Clean up data associated with an authority load
! 204: */
! 205: static void free_load_data(load_data_t *data)
! 206: {
! 207: if (data->authority)
! 208: {
! 209: authority_destroy(data->authority);
! 210: }
! 211: free(data->handle);
! 212: free(data->module);
! 213: free(data->file);
! 214: free(data);
! 215: }
! 216:
! 217: /**
! 218: * Parse a string
! 219: */
! 220: CALLBACK(parse_string, bool,
! 221: char **str, chunk_t v)
! 222: {
! 223: if (!chunk_printable(v, NULL, ' '))
! 224: {
! 225: return FALSE;
! 226: }
! 227: *str = strndup(v.ptr, v.len);
! 228:
! 229: return TRUE;
! 230: }
! 231:
! 232: /**
! 233: * Parse a uint32_t
! 234: */
! 235: CALLBACK(parse_uint32, bool,
! 236: uint32_t *out, chunk_t v)
! 237: {
! 238: char buf[16], *end;
! 239: u_long l;
! 240:
! 241: if (!vici_stringify(v, buf, sizeof(buf)))
! 242: {
! 243: return FALSE;
! 244: }
! 245: l = strtoul(buf, &end, 0);
! 246: if (*end == 0)
! 247: {
! 248: *out = l;
! 249: return TRUE;
! 250: }
! 251: return FALSE;
! 252: }
! 253:
! 254: /**
! 255: * Parse list of URIs
! 256: */
! 257: CALLBACK(parse_uris, bool,
! 258: linked_list_t *out, chunk_t v)
! 259: {
! 260: char *uri;
! 261:
! 262: if (!chunk_printable(v, NULL, ' '))
! 263: {
! 264: return FALSE;
! 265: }
! 266: uri = strndup(v.ptr, v.len);
! 267: out->insert_last(out, uri);
! 268:
! 269: return TRUE;
! 270: }
! 271:
! 272: /**
! 273: * Parse a CA certificate
! 274: */
! 275: CALLBACK(parse_cacert, bool,
! 276: certificate_t **cacert, chunk_t v)
! 277: {
! 278: certificate_t *cert;
! 279: x509_t *x509;
! 280:
! 281: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 282: BUILD_BLOB_PEM, v, BUILD_END);
! 283: if (!cert)
! 284: {
! 285: return create_reply("parsing %N certificate failed",
! 286: certificate_type_names, CERT_X509);
! 287: }
! 288: x509 = (x509_t*)cert;
! 289:
! 290: if ((x509->get_flags(x509) & X509_CA) != X509_CA)
! 291: {
! 292: cert->destroy(cert);
! 293: return create_reply("certificate without CA flag, rejected");
! 294: }
! 295: *cacert = cert;
! 296:
! 297: return TRUE;
! 298: }
! 299:
! 300: CALLBACK(authority_kv, bool,
! 301: load_data_t *data, vici_message_t *message, char *name, chunk_t value)
! 302: {
! 303: parse_rule_t rules[] = {
! 304: { "cacert", parse_cacert, &data->authority->cert },
! 305: { "file", parse_string, &data->file },
! 306: { "handle", parse_string, &data->handle },
! 307: { "slot", parse_uint32, &data->slot },
! 308: { "module", parse_string, &data->module },
! 309: { "cert_uri_base", parse_string, &data->authority->cert_uri_base },
! 310: };
! 311:
! 312: return parse_rules(rules, countof(rules), name, value,
! 313: &data->request->reply);
! 314: }
! 315:
! 316: CALLBACK(authority_li, bool,
! 317: load_data_t *data, vici_message_t *message, char *name, chunk_t value)
! 318: {
! 319: parse_rule_t rules[] = {
! 320: { "crl_uris", parse_uris, data->authority->crl_uris },
! 321: { "ocsp_uris", parse_uris, data->authority->ocsp_uris },
! 322: };
! 323:
! 324: return parse_rules(rules, countof(rules), name, value,
! 325: &data->request->reply);
! 326: }
! 327:
! 328: static void log_authority_data(authority_t *authority)
! 329: {
! 330: enumerator_t *enumerator;
! 331: identification_t *subject;
! 332: bool first = TRUE;
! 333: char *uri;
! 334:
! 335: subject = authority->cert->get_subject(authority->cert);
! 336: DBG2(DBG_CFG, " cacert = %Y", subject);
! 337:
! 338: enumerator = authority->crl_uris->create_enumerator(authority->crl_uris);
! 339: while (enumerator->enumerate(enumerator, &uri))
! 340: {
! 341: if (first)
! 342: {
! 343: DBG2(DBG_CFG, " crl_uris = %s", uri);
! 344: first = FALSE;
! 345: }
! 346: else
! 347: {
! 348: DBG2(DBG_CFG, " %s", uri);
! 349: }
! 350: }
! 351: enumerator->destroy(enumerator);
! 352:
! 353: first = TRUE;
! 354: enumerator = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
! 355: while (enumerator->enumerate(enumerator, &uri))
! 356: {
! 357: if (first)
! 358: {
! 359: DBG2(DBG_CFG, " ocsp_uris = %s", uri);
! 360: first = FALSE;
! 361: }
! 362: else
! 363: {
! 364: DBG2(DBG_CFG, " %s", uri);
! 365: }
! 366: }
! 367: enumerator->destroy(enumerator);
! 368:
! 369: if (authority->cert_uri_base)
! 370: {
! 371: DBG2(DBG_CFG, " cert_uri_base = %s", authority->cert_uri_base);
! 372: }
! 373: }
! 374:
! 375: CALLBACK(authority_sn, bool,
! 376: request_data_t *request, vici_message_t *message,
! 377: vici_parse_context_t *ctx, char *name)
! 378: {
! 379: enumerator_t *enumerator;
! 380: linked_list_t *authorities;
! 381: authority_t *authority;
! 382: vici_cred_t *cred;
! 383: load_data_t *data;
! 384: chunk_t handle;
! 385:
! 386: INIT(data,
! 387: .request = request,
! 388: .authority = authority_create(name),
! 389: .slot = -1,
! 390: );
! 391:
! 392: DBG2(DBG_CFG, " authority %s:", name);
! 393:
! 394: if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data))
! 395: {
! 396: free_load_data(data);
! 397: return FALSE;
! 398: }
! 399: if (!data->authority->cert)
! 400: {
! 401: if (data->file)
! 402: {
! 403: data->authority->cert = lib->creds->create(lib->creds,
! 404: CRED_CERTIFICATE, CERT_X509,
! 405: BUILD_FROM_FILE, data->file, BUILD_END);
! 406: }
! 407: else if (data->handle)
! 408: {
! 409: handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
! 410: if (data->slot != -1)
! 411: {
! 412: data->authority->cert = lib->creds->create(lib->creds,
! 413: CRED_CERTIFICATE, CERT_X509,
! 414: BUILD_PKCS11_KEYID, handle,
! 415: BUILD_PKCS11_SLOT, data->slot,
! 416: data->module ? BUILD_PKCS11_MODULE : BUILD_END,
! 417: data->module, BUILD_END);
! 418: }
! 419: else
! 420: {
! 421: data->authority->cert = lib->creds->create(lib->creds,
! 422: CRED_CERTIFICATE, CERT_X509,
! 423: BUILD_PKCS11_KEYID, handle,
! 424: data->module ? BUILD_PKCS11_MODULE : BUILD_END,
! 425: data->module, BUILD_END);
! 426: }
! 427: chunk_free(&handle);
! 428: }
! 429: }
! 430: if (!data->authority->cert)
! 431: {
! 432: request->reply = create_reply("CA certificate missing: %s", name);
! 433: free_load_data(data);
! 434: return FALSE;
! 435: }
! 436: log_authority_data(data->authority);
! 437:
! 438: request->this->lock->write_lock(request->this->lock);
! 439:
! 440: authorities = request->this->authorities;
! 441: enumerator = authorities->create_enumerator(authorities);
! 442: while (enumerator->enumerate(enumerator, &authority))
! 443: {
! 444: if (streq(authority->name, name))
! 445: {
! 446: /* remove the old authority definition */
! 447: authorities->remove_at(authorities, enumerator);
! 448: authority_destroy(authority);
! 449: break;
! 450: }
! 451: }
! 452: enumerator->destroy(enumerator);
! 453: authorities->insert_last(authorities, data->authority);
! 454:
! 455: cred = request->this->cred;
! 456: data->authority->cert = cred->add_cert(cred, data->authority->cert);
! 457: data->authority = NULL;
! 458:
! 459: request->this->lock->unlock(request->this->lock);
! 460: free_load_data(data);
! 461:
! 462: return TRUE;
! 463: }
! 464:
! 465: CALLBACK(load_authority, vici_message_t*,
! 466: private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
! 467: {
! 468: request_data_t request = {
! 469: .this = this,
! 470: };
! 471:
! 472: if (!message->parse(message, NULL, authority_sn, NULL, NULL, &request))
! 473: {
! 474: if (request.reply)
! 475: {
! 476: return request.reply;
! 477: }
! 478: return create_reply("parsing request failed");
! 479: }
! 480: return create_reply(NULL);
! 481: }
! 482:
! 483: CALLBACK(unload_authority, vici_message_t*,
! 484: private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
! 485: {
! 486: enumerator_t *enumerator;
! 487: authority_t *authority;
! 488: char *authority_name;
! 489: bool found = FALSE;
! 490:
! 491: authority_name = message->get_str(message, NULL, "name");
! 492: if (!authority_name)
! 493: {
! 494: return create_reply("unload: missing authority name");
! 495: }
! 496:
! 497: this->lock->write_lock(this->lock);
! 498: enumerator = this->authorities->create_enumerator(this->authorities);
! 499: while (enumerator->enumerate(enumerator, &authority))
! 500: {
! 501: if (streq(authority->name, authority_name))
! 502: {
! 503: this->authorities->remove_at(this->authorities, enumerator);
! 504: authority_destroy(authority);
! 505: found = TRUE;
! 506: break;
! 507: }
! 508: }
! 509: enumerator->destroy(enumerator);
! 510: this->lock->unlock(this->lock);
! 511:
! 512: if (!found)
! 513: {
! 514: return create_reply("unload: authority '%s' not found", authority_name);
! 515: }
! 516: return create_reply(NULL);
! 517: }
! 518:
! 519: CALLBACK(get_authorities, vici_message_t*,
! 520: private_vici_authority_t *this, char *name, u_int id,
! 521: vici_message_t *message)
! 522: {
! 523: vici_builder_t *builder;
! 524: enumerator_t *enumerator;
! 525: authority_t *authority;
! 526:
! 527: builder = vici_builder_create();
! 528: builder->begin_list(builder, "authorities");
! 529:
! 530: this->lock->read_lock(this->lock);
! 531: enumerator = this->authorities->create_enumerator(this->authorities);
! 532: while (enumerator->enumerate(enumerator, &authority))
! 533: {
! 534: builder->add_li(builder, "%s", authority->name);
! 535: }
! 536: enumerator->destroy(enumerator);
! 537: this->lock->unlock(this->lock);
! 538:
! 539: builder->end_list(builder);
! 540:
! 541: return builder->finalize(builder);
! 542: }
! 543:
! 544: CALLBACK(list_authorities, vici_message_t*,
! 545: private_vici_authority_t *this, char *name, u_int id, vici_message_t *request)
! 546: {
! 547: enumerator_t *enumerator, *e;
! 548: authority_t *authority;
! 549: vici_builder_t *b;
! 550: char *str, *uri;
! 551:
! 552: str = request->get_str(request, NULL, "name");
! 553:
! 554: this->lock->read_lock(this->lock);
! 555: enumerator = this->authorities->create_enumerator(this->authorities);
! 556: while (enumerator->enumerate(enumerator, &authority))
! 557: {
! 558: if (str && !streq(str, authority->name))
! 559: {
! 560: continue;
! 561: }
! 562: b = vici_builder_create();
! 563:
! 564: /* open authority section */
! 565: b->begin_section(b, authority->name);
! 566:
! 567: /* subject DN of cacert */
! 568: b->add_kv(b, "cacert", "%Y",
! 569: authority->cert->get_subject(authority->cert));
! 570:
! 571: /* list of crl_uris */
! 572: b->begin_list(b, "crl_uris");
! 573: e = authority->crl_uris->create_enumerator(authority->crl_uris);
! 574: while (e->enumerate(e, &uri))
! 575: {
! 576: b->add_li(b, "%s", uri);
! 577: }
! 578: e->destroy(e);
! 579: b->end_list(b);
! 580:
! 581: /* list of ocsp_uris */
! 582: b->begin_list(b, "ocsp_uris");
! 583: e = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
! 584: while (e->enumerate(e, &uri))
! 585: {
! 586: b->add_li(b, "%s", uri);
! 587: }
! 588: e->destroy(e);
! 589: b->end_list(b);
! 590:
! 591: /* cert_uri_base */
! 592: if (authority->cert_uri_base)
! 593: {
! 594: b->add_kv(b, "cert_uri_base", "%s", authority->cert_uri_base);
! 595: }
! 596:
! 597: /* close authority and raise event */
! 598: b->end_section(b);
! 599: this->dispatcher->raise_event(this->dispatcher, "list-authority", id,
! 600: b->finalize(b));
! 601: }
! 602: enumerator->destroy(enumerator);
! 603: this->lock->unlock(this->lock);
! 604:
! 605: b = vici_builder_create();
! 606: return b->finalize(b);
! 607: }
! 608:
! 609: static void manage_command(private_vici_authority_t *this,
! 610: char *name, vici_command_cb_t cb, bool reg)
! 611: {
! 612: this->dispatcher->manage_command(this->dispatcher, name,
! 613: reg ? cb : NULL, this);
! 614: }
! 615:
! 616: /**
! 617: * (Un-)register dispatcher functions
! 618: */
! 619: static void manage_commands(private_vici_authority_t *this, bool reg)
! 620: {
! 621: this->dispatcher->manage_event(this->dispatcher, "list-authority", reg);
! 622:
! 623: manage_command(this, "load-authority", load_authority, reg);
! 624: manage_command(this, "unload-authority", unload_authority, reg);
! 625: manage_command(this, "get-authorities", get_authorities, reg);
! 626: manage_command(this, "list-authorities", list_authorities, reg);
! 627: }
! 628:
! 629: /**
! 630: * data to pass to create_inner_cdp
! 631: */
! 632: typedef struct {
! 633: private_vici_authority_t *this;
! 634: certificate_type_t type;
! 635: identification_t *id;
! 636: } cdp_data_t;
! 637:
! 638: /**
! 639: * destroy cdp enumerator data and unlock list
! 640: */
! 641: static void cdp_data_destroy(cdp_data_t *data)
! 642: {
! 643: data->this->lock->unlock(data->this->lock);
! 644: free(data);
! 645: }
! 646:
! 647: /**
! 648: * inner enumerator constructor for CDP URIs
! 649: */
! 650: static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data)
! 651: {
! 652: public_key_t *public;
! 653: enumerator_t *enumerator = NULL;
! 654: linked_list_t *list;
! 655:
! 656: if (data->type == CERT_X509_OCSP_RESPONSE)
! 657: {
! 658: list = authority->ocsp_uris;
! 659: }
! 660: else
! 661: {
! 662: list = authority->crl_uris;
! 663: }
! 664:
! 665: public = authority->cert->get_public_key(authority->cert);
! 666: if (public)
! 667: {
! 668: if (!data->id)
! 669: {
! 670: enumerator = list->create_enumerator(list);
! 671: }
! 672: else
! 673: {
! 674: if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
! 675: {
! 676: enumerator = list->create_enumerator(list);
! 677: }
! 678: }
! 679: public->destroy(public);
! 680: }
! 681: return enumerator;
! 682: }
! 683:
! 684: /**
! 685: * inner enumerator constructor for "Hash and URL"
! 686: */
! 687: static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority,
! 688: cdp_data_t *data)
! 689: {
! 690: enumerator_t *enumerator = NULL;
! 691:
! 692: if (!data->id || !authority->cert_uri_base)
! 693: {
! 694: return NULL;
! 695: }
! 696:
! 697: if (authority->cert->has_subject(authority->cert, data->id) != ID_MATCH_NONE)
! 698: {
! 699: enumerator = enumerator_create_single(strdup(authority->cert_uri_base),
! 700: free);
! 701: }
! 702: return enumerator;
! 703: }
! 704:
! 705: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
! 706: private_vici_authority_t *this, certificate_type_t type,
! 707: identification_t *id)
! 708: {
! 709: cdp_data_t *data;
! 710:
! 711: switch (type)
! 712: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
! 713: case CERT_X509:
! 714: case CERT_X509_CRL:
! 715: case CERT_X509_OCSP_RESPONSE:
! 716: case CERT_ANY:
! 717: break;
! 718: default:
! 719: return NULL;
! 720: }
! 721: data = malloc_thing(cdp_data_t);
! 722: data->this = this;
! 723: data->type = type;
! 724: data->id = id;
! 725:
! 726: this->lock->read_lock(this->lock);
! 727:
! 728: return enumerator_create_nested(
! 729: this->authorities->create_enumerator(this->authorities),
! 730: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl :
! 731: (void*)create_inner_cdp, data, (void*)cdp_data_destroy);
! 732: }
! 733:
! 734: METHOD(vici_authority_t, destroy, void,
! 735: private_vici_authority_t *this)
! 736: {
! 737: manage_commands(this, FALSE);
! 738:
! 739: this->authorities->destroy_function(this->authorities,
! 740: (void*)authority_destroy);
! 741: this->lock->destroy(this->lock);
! 742: free(this);
! 743: }
! 744:
! 745: /**
! 746: * See header
! 747: */
! 748: vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
! 749: vici_cred_t *cred)
! 750: {
! 751: private_vici_authority_t *this;
! 752:
! 753: INIT(this,
! 754: .public = {
! 755: .set = {
! 756: .create_private_enumerator = (void*)return_null,
! 757: .create_cert_enumerator = (void*)return_null,
! 758: .create_shared_enumerator = (void*)return_null,
! 759: .create_cdp_enumerator = _create_cdp_enumerator,
! 760: .cache_cert = (void*)nop,
! 761: },
! 762: .destroy = _destroy,
! 763: },
! 764: .dispatcher = dispatcher,
! 765: .cred = cred,
! 766: .authorities = linked_list_create(),
! 767: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
! 768: );
! 769:
! 770: manage_commands(this, TRUE);
! 771:
! 772: return &this->public;
! 773: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>