Annotation of embedaddon/strongswan/src/libstrongswan/plugins/plugin_feature.h, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2015 Tobias Brunner
! 3: * Copyright (C) 2016-2019 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * Copyright (C) 2011 Martin Willi
! 7: * Copyright (C) 2011 revosec AG
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify it
! 10: * under the terms of the GNU General Public License as published by the
! 11: * Free Software Foundation; either version 2 of the License, or (at your
! 12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 13: *
! 14: * This program is distributed in the hope that it will be useful, but
! 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 17: * for more details.
! 18: */
! 19:
! 20: /**
! 21: * @defgroup plugin_feature plugin_feature
! 22: * @{ @ingroup plugins
! 23: */
! 24:
! 25: #ifndef PLUGIN_FEATURE_H_
! 26: #define PLUGIN_FEATURE_H_
! 27:
! 28: typedef struct plugin_feature_t plugin_feature_t;
! 29:
! 30: #include <library.h>
! 31: #include <eap/eap.h>
! 32: #include <plugins/plugin.h>
! 33: #include <credentials/containers/container.h>
! 34:
! 35: /**
! 36: * Callback function of a plugin to (un-)register a specified feature.
! 37: *
! 38: * @param plugin plugin instance
! 39: * @param feature feature to register
! 40: * @param reg TRUE to register, FALSE to unregister
! 41: * @param cb_data user data passed with callback function
! 42: * @return TRUE if registered successfully
! 43: */
! 44: typedef bool (*plugin_feature_callback_t)(plugin_t *plugin,
! 45: plugin_feature_t *feature,
! 46: bool reg,void *cb_data);
! 47:
! 48: /**
! 49: * Feature a plugin provides or depends on, including registration functions.
! 50: *
! 51: * Each plugin returns a list of plugin features, allowing the plugin loader
! 52: * to resolve dependencies and register the feature. FEATURE_PROVIDE defines
! 53: * features provided by the plugin, hard (DEPENDS) or soft (SDEPEND) dependency
! 54: * specified is related to the previously defined PROVIDE feature.
! 55: * If a plugin feature requires to hook in functionality into the library
! 56: * or a daemon, it can use REGISTER or CALLBACK entries. Each PROVIDE feature
! 57: * uses the REGISTER/CALLBACK entry defined previously. The REGISTER entry
! 58: * defines a common feature registration function directly passed to the
! 59: * associated manager or factory (crypto/credential factory etc.). A callback
! 60: * function is more generic allows the loader to invoke a callback to do
! 61: * the registration. PROVIDE features that do not use a registration or callback
! 62: * function must be listed before any REGISTER/CALLBACK entry, or use the NOOP
! 63: * helper macro.
! 64: *
! 65: * To conveniently create feature lists, use the macros PLUGIN_REGISTER,
! 66: * PLUGIN_CALLBACK, PLUGIN_NOOP, PLUGIN_PROVIDE, PLUGIN_DEPENDS and
! 67: * PLUGIN_SDEPEND. Use indentation to show how the registration functions
! 68: * and dependencies are related to a provided feature, such as:
! 69: *
! 70: * @verbatim
! 71: // two features, one with two dependencies, both use a callback to register
! 72: PLUGIN_CALLBACK(...),
! 73: PLUGIN_PROVIDE(...),
! 74: PLUGIN_DEPENDS(...),
! 75: PLUGIN_SDEPEND(...),
! 76: PLUGIN_PROVIDE(...),
! 77: // common constructor to register for a feature with one dependency
! 78: PLUGIN_REGISTER(...),
! 79: PLUGIN_PROVIDE(...),
! 80: PLUGIN_DEPENDS(...),
! 81: // feature that does not use a registration function
! 82: PLUGIN_NOOP,
! 83: PLUGIN_PROVIDE(...),
! 84: @endverbatim
! 85: */
! 86: struct plugin_feature_t {
! 87: /** kind of entry */
! 88: enum {
! 89: /* plugin provides this feature */
! 90: FEATURE_PROVIDE,
! 91: /* a feature depends on this feature, hard dependency */
! 92: FEATURE_DEPENDS,
! 93: /* a feature can optionally use this feature, soft dependency */
! 94: FEATURE_SDEPEND,
! 95: /* register the specified function for all following features */
! 96: FEATURE_REGISTER,
! 97: /* use a callback to register all following features */
! 98: FEATURE_CALLBACK,
! 99: } kind;
! 100: /* type of feature */
! 101: enum {
! 102: /** not a feature */
! 103: FEATURE_NONE,
! 104: /** crypter_t */
! 105: FEATURE_CRYPTER,
! 106: /** aead_t */
! 107: FEATURE_AEAD,
! 108: /** signer_t */
! 109: FEATURE_SIGNER,
! 110: /** hasher_t */
! 111: FEATURE_HASHER,
! 112: /** prf_t */
! 113: FEATURE_PRF,
! 114: /** xof_t */
! 115: FEATURE_XOF,
! 116: /** drbg_t */
! 117: FEATURE_DRBG,
! 118: /** diffie_hellman_t */
! 119: FEATURE_DH,
! 120: /** rng_t */
! 121: FEATURE_RNG,
! 122: /** nonce_gen_t */
! 123: FEATURE_NONCE_GEN,
! 124: /** generic private key support */
! 125: FEATURE_PRIVKEY,
! 126: /** generating new private keys */
! 127: FEATURE_PRIVKEY_GEN,
! 128: /** private_key_t->sign() */
! 129: FEATURE_PRIVKEY_SIGN,
! 130: /** private_key_t->decrypt() */
! 131: FEATURE_PRIVKEY_DECRYPT,
! 132: /** generic public key support */
! 133: FEATURE_PUBKEY,
! 134: /** public_key_t->verify() */
! 135: FEATURE_PUBKEY_VERIFY,
! 136: /** public_key_t->encrypt() */
! 137: FEATURE_PUBKEY_ENCRYPT,
! 138: /** parsing certificates */
! 139: FEATURE_CERT_DECODE,
! 140: /** generating certificates */
! 141: FEATURE_CERT_ENCODE,
! 142: /** parsing containers */
! 143: FEATURE_CONTAINER_DECODE,
! 144: /** generating containers */
! 145: FEATURE_CONTAINER_ENCODE,
! 146: /** EAP server implementation */
! 147: FEATURE_EAP_SERVER,
! 148: /** EAP peer implementation */
! 149: FEATURE_EAP_PEER,
! 150: /** XAuth server implementation */
! 151: FEATURE_XAUTH_SERVER,
! 152: /** XAuth peer implementation */
! 153: FEATURE_XAUTH_PEER,
! 154: /** database_t */
! 155: FEATURE_DATABASE,
! 156: /** fetcher_t */
! 157: FEATURE_FETCHER,
! 158: /** resolver_t */
! 159: FEATURE_RESOLVER,
! 160: /** custom feature, described with a string */
! 161: FEATURE_CUSTOM,
! 162: } type;
! 163: /** More specific data for each type */
! 164: union {
! 165: /** FEATURE_CRYPTER */
! 166: struct {
! 167: encryption_algorithm_t alg;
! 168: size_t key_size;
! 169: } crypter;
! 170: /** FEATURE_AEAD */
! 171: struct {
! 172: encryption_algorithm_t alg;
! 173: size_t key_size;
! 174: } aead;
! 175: /** FEATURE_SIGNER */
! 176: integrity_algorithm_t signer;
! 177: /** FEATURE_PRF */
! 178: pseudo_random_function_t prf;
! 179: /** FEATURE_XOFF */
! 180: ext_out_function_t xof;
! 181: /** FEATURE_DRBG */
! 182: drbg_type_t drbg;
! 183: /** FEATURE_HASHER */
! 184: hash_algorithm_t hasher;
! 185: /** FEATURE_DH */
! 186: diffie_hellman_group_t dh_group;
! 187: /** FEATURE_RNG */
! 188: rng_quality_t rng_quality;
! 189: /** FEATURE_PRIVKEY */
! 190: key_type_t privkey;
! 191: /** FEATURE_PRIVKEY_GEN */
! 192: key_type_t privkey_gen;
! 193: /** FEATURE_PRIVKEY_SIGN */
! 194: signature_scheme_t privkey_sign;
! 195: /** FEATURE_PRIVKEY_DECRYPT */
! 196: encryption_scheme_t privkey_decrypt;
! 197: /** FEATURE_PUBKEY */
! 198: key_type_t pubkey;
! 199: /** FEATURE_PUBKEY_VERIFY */
! 200: signature_scheme_t pubkey_verify;
! 201: /** FEATURE_PUBKEY_ENCRYPT */
! 202: encryption_scheme_t pubkey_encrypt;
! 203: /** FEATURE_CERT_DECODE/ENCODE */
! 204: certificate_type_t cert;
! 205: /** FEATURE_CONTAINER_DECODE/ENCODE */
! 206: container_type_t container;
! 207: /** FEATURE_EAP_SERVER/CLIENT */
! 208: eap_vendor_type_t eap;
! 209: /** FEATURE_DATABASE */
! 210: db_driver_t database;
! 211: /** FEATURE_FETCHER */
! 212: char *fetcher;
! 213: /** FEATURE_CUSTOM */
! 214: char *custom;
! 215: /** FEATURE_XAUTH_SERVER/CLIENT */
! 216: char *xauth;
! 217:
! 218: /** FEATURE_REGISTER */
! 219: struct {
! 220: /** final flag to pass for builder_function_t */
! 221: bool final;
! 222: /** feature specific function to register for this type */
! 223: void *f;
! 224: } reg;
! 225:
! 226: /** FEATURE_CALLBACK */
! 227: struct {
! 228: /** callback function to invoke for registration */
! 229: plugin_feature_callback_t f;
! 230: /** data to pass to callback */
! 231: void *data;
! 232: } cb;
! 233: } arg;
! 234: };
! 235:
! 236: #define FEATURE(kind, type, ...) _PLUGIN_FEATURE_##type(kind, __VA_ARGS__)
! 237:
! 238: /**
! 239: * Define function to register directly for all upcoming features.
! 240: *
! 241: * @param type feature type to register
! 242: * @param f type specific function to register
! 243: * @param ... type specific additional arguments
! 244: */
! 245: #define PLUGIN_REGISTER(type, f, ...) _PLUGIN_FEATURE_REGISTER_##type(type, f, ##__VA_ARGS__)
! 246:
! 247: /**
! 248: * Define a callback to invoke for registering all upcoming features.
! 249: *
! 250: * @param cb type specific callback function to register
! 251: * @param data data pointer to pass to callback
! 252: */
! 253: #define PLUGIN_CALLBACK(cb, data) _PLUGIN_FEATURE_CALLBACK(cb, data)
! 254:
! 255: /**
! 256: * The upcoming features use neither a callback nor a register function.
! 257: */
! 258: #define PLUGIN_NOOP _PLUGIN_FEATURE_CALLBACK(NULL, NULL)
! 259:
! 260: /**
! 261: * Define a feature the plugin provides.
! 262: *
! 263: * @param type feature type to provide
! 264: * @param ... type specific arguments
! 265: */
! 266: #define PLUGIN_PROVIDE(type, ...) _PLUGIN_FEATURE_##type(PROVIDE, __VA_ARGS__)
! 267:
! 268: /**
! 269: * Define a hard dependency for the previously defined feature.
! 270: *
! 271: * @param type feature type to provide
! 272: * @param ... type specific arguments
! 273: */
! 274: #define PLUGIN_DEPENDS(type, ...) _PLUGIN_FEATURE_##type(DEPENDS, __VA_ARGS__)
! 275:
! 276: /**
! 277: * Define a soft dependency for the previously defined feature.
! 278: *
! 279: * @param type feature type to provide
! 280: * @param ... type specific arguments
! 281: */
! 282: #define PLUGIN_SDEPEND(type, ...) _PLUGIN_FEATURE_##type(SDEPEND, __VA_ARGS__)
! 283:
! 284: #define __PLUGIN_FEATURE(kind, type, ...) (plugin_feature_t){ FEATURE_##kind, FEATURE_##type, { __VA_ARGS__ }}
! 285: #define _PLUGIN_FEATURE_CRYPTER(kind, alg, size) __PLUGIN_FEATURE(kind, CRYPTER, .crypter = { alg, size })
! 286: #define _PLUGIN_FEATURE_AEAD(kind, alg, size) __PLUGIN_FEATURE(kind, AEAD, .aead = { alg, size })
! 287: #define _PLUGIN_FEATURE_SIGNER(kind, alg) __PLUGIN_FEATURE(kind, SIGNER, .signer = alg)
! 288: #define _PLUGIN_FEATURE_HASHER(kind, alg) __PLUGIN_FEATURE(kind, HASHER, .hasher = alg)
! 289: #define _PLUGIN_FEATURE_PRF(kind, alg) __PLUGIN_FEATURE(kind, PRF, .prf = alg)
! 290: #define _PLUGIN_FEATURE_XOF(kind, alg) __PLUGIN_FEATURE(kind, XOF, .xof = alg)
! 291: #define _PLUGIN_FEATURE_DRBG(kind, type) __PLUGIN_FEATURE(kind, DRBG, .drbg = type)
! 292: #define _PLUGIN_FEATURE_DH(kind, group) __PLUGIN_FEATURE(kind, DH, .dh_group = group)
! 293: #define _PLUGIN_FEATURE_RNG(kind, quality) __PLUGIN_FEATURE(kind, RNG, .rng_quality = quality)
! 294: #define _PLUGIN_FEATURE_NONCE_GEN(kind, ...) __PLUGIN_FEATURE(kind, NONCE_GEN, .custom = NULL)
! 295: #define _PLUGIN_FEATURE_PRIVKEY(kind, type) __PLUGIN_FEATURE(kind, PRIVKEY, .privkey = type)
! 296: #define _PLUGIN_FEATURE_PRIVKEY_GEN(kind, type) __PLUGIN_FEATURE(kind, PRIVKEY_GEN, .privkey_gen = type)
! 297: #define _PLUGIN_FEATURE_PRIVKEY_SIGN(kind, scheme) __PLUGIN_FEATURE(kind, PRIVKEY_SIGN, .privkey_sign = scheme)
! 298: #define _PLUGIN_FEATURE_PRIVKEY_DECRYPT(kind, scheme) __PLUGIN_FEATURE(kind, PRIVKEY_DECRYPT, .privkey_decrypt = scheme)
! 299: #define _PLUGIN_FEATURE_PUBKEY(kind, type) __PLUGIN_FEATURE(kind, PUBKEY, .pubkey = type)
! 300: #define _PLUGIN_FEATURE_PUBKEY_VERIFY(kind, scheme) __PLUGIN_FEATURE(kind, PUBKEY_VERIFY, .pubkey_verify = scheme)
! 301: #define _PLUGIN_FEATURE_PUBKEY_ENCRYPT(kind, scheme) __PLUGIN_FEATURE(kind, PUBKEY_ENCRYPT, .pubkey_encrypt = scheme)
! 302: #define _PLUGIN_FEATURE_CERT_DECODE(kind, type) __PLUGIN_FEATURE(kind, CERT_DECODE, .cert = type)
! 303: #define _PLUGIN_FEATURE_CERT_ENCODE(kind, type) __PLUGIN_FEATURE(kind, CERT_ENCODE, .cert = type)
! 304: #define _PLUGIN_FEATURE_CONTAINER_DECODE(kind, type) __PLUGIN_FEATURE(kind, CONTAINER_DECODE, .container = type)
! 305: #define _PLUGIN_FEATURE_CONTAINER_ENCODE(kind, type) __PLUGIN_FEATURE(kind, CONTAINER_ENCODE, .container = type)
! 306: #define _PLUGIN_FEATURE_EAP_SERVER(kind, type) _PLUGIN_FEATURE_EAP_SERVER_VENDOR(kind, type, 0)
! 307: #define _PLUGIN_FEATURE_EAP_PEER(kind, type) _PLUGIN_FEATURE_EAP_PEER_VENDOR(kind, type, 0)
! 308: #define _PLUGIN_FEATURE_EAP_SERVER_VENDOR(kind, type, vendor)__PLUGIN_FEATURE(kind, EAP_SERVER, .eap = { type, vendor })
! 309: #define _PLUGIN_FEATURE_EAP_PEER_VENDOR(kind, type, vendor) __PLUGIN_FEATURE(kind, EAP_PEER, .eap = { type, vendor })
! 310: #define _PLUGIN_FEATURE_DATABASE(kind, type) __PLUGIN_FEATURE(kind, DATABASE, .database = type)
! 311: #define _PLUGIN_FEATURE_FETCHER(kind, type) __PLUGIN_FEATURE(kind, FETCHER, .fetcher = type)
! 312: #define _PLUGIN_FEATURE_RESOLVER(kind, ...) __PLUGIN_FEATURE(kind, RESOLVER, .custom = NULL)
! 313: #define _PLUGIN_FEATURE_CUSTOM(kind, name) __PLUGIN_FEATURE(kind, CUSTOM, .custom = name)
! 314: #define _PLUGIN_FEATURE_XAUTH_SERVER(kind, name) __PLUGIN_FEATURE(kind, XAUTH_SERVER, .xauth = name)
! 315: #define _PLUGIN_FEATURE_XAUTH_PEER(kind, name) __PLUGIN_FEATURE(kind, XAUTH_PEER, .xauth = name)
! 316:
! 317: #define __PLUGIN_FEATURE_REGISTER(type, _f) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg.f = _f }
! 318: #define __PLUGIN_FEATURE_REGISTER_BUILDER(type, _f, _final) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg = {.f = _f, .final = _final, }}
! 319: #define _PLUGIN_FEATURE_REGISTER_CRYPTER(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 320: #define _PLUGIN_FEATURE_REGISTER_AEAD(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 321: #define _PLUGIN_FEATURE_REGISTER_SIGNER(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 322: #define _PLUGIN_FEATURE_REGISTER_HASHER(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 323: #define _PLUGIN_FEATURE_REGISTER_PRF(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 324: #define _PLUGIN_FEATURE_REGISTER_XOF(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 325: #define _PLUGIN_FEATURE_REGISTER_DRBG(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 326: #define _PLUGIN_FEATURE_REGISTER_DH(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 327: #define _PLUGIN_FEATURE_REGISTER_RNG(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 328: #define _PLUGIN_FEATURE_REGISTER_NONCE_GEN(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 329: #define _PLUGIN_FEATURE_REGISTER_PRIVKEY(type, f, final) __PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 330: #define _PLUGIN_FEATURE_REGISTER_PRIVKEY_GEN(type, f, final)__PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 331: #define _PLUGIN_FEATURE_REGISTER_PUBKEY(type, f, final) __PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 332: #define _PLUGIN_FEATURE_REGISTER_CERT_DECODE(type, f, final)__PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 333: #define _PLUGIN_FEATURE_REGISTER_CERT_ENCODE(type, f, final)__PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 334: #define _PLUGIN_FEATURE_REGISTER_CONTAINER_DECODE(type, f, final)__PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 335: #define _PLUGIN_FEATURE_REGISTER_CONTAINER_ENCODE(type, f, final)__PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final)
! 336: #define _PLUGIN_FEATURE_REGISTER_DATABASE(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 337: #define _PLUGIN_FEATURE_REGISTER_FETCHER(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 338: #define _PLUGIN_FEATURE_REGISTER_RESOLVER(type, f) __PLUGIN_FEATURE_REGISTER(type, f)
! 339:
! 340: #define _PLUGIN_FEATURE_CALLBACK(_cb, _data) (plugin_feature_t){ FEATURE_CALLBACK, FEATURE_NONE, .arg.cb = { .f = _cb, .data = _data } }
! 341:
! 342: /**
! 343: * Names for plugin_feature_t types.
! 344: */
! 345: extern enum_name_t *plugin_feature_names;
! 346:
! 347: /**
! 348: * Add a set of plugin features to the given array, which must have enough space
! 349: * to store the added features.
! 350: *
! 351: * @param features the array of plugin features to extend
! 352: * @param to_add the features to add
! 353: * @param count number of features to add
! 354: * @param pos current position in the features array, gets advanced
! 355: */
! 356: static inline void plugin_features_add(plugin_feature_t *features,
! 357: plugin_feature_t *to_add,
! 358: int count, int *pos)
! 359: {
! 360: int i;
! 361:
! 362: for (i = 0; i < count; i++)
! 363: {
! 364: features[(*pos)++] = to_add[i];
! 365: }
! 366: }
! 367:
! 368: /**
! 369: * Calculates a hash value for the given feature.
! 370: *
! 371: * Since this is intended to be used with the plugin_features_matches function
! 372: * the hash is not really unique for all types of features (e.g. RNGs are all
! 373: * mapped to the same value because they are loosely matched by said function).
! 374: *
! 375: * @param feature feature to hash
! 376: * @return hash value of the feature
! 377: */
! 378: uint32_t plugin_feature_hash(plugin_feature_t *feature);
! 379:
! 380: /**
! 381: * Check if feature a matches to feature b.
! 382: *
! 383: * This is no check for equality. For instance, for FEATURE_RNG a matches b if
! 384: * a's strength is at least the strength of b. Or for FEATURE_SQL if a is
! 385: * DB_ANY it will match b if it is of the same type.
! 386: *
! 387: * @param a feature to check
! 388: * @param b feature to match against
! 389: * @return TRUE if a matches b
! 390: */
! 391: bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b);
! 392:
! 393: /**
! 394: * Check if feature a equals feature b.
! 395: *
! 396: * @param a feature
! 397: * @param b feature to compare
! 398: * @return TRUE if a equals b
! 399: */
! 400: bool plugin_feature_equals(plugin_feature_t *a, plugin_feature_t *b);
! 401:
! 402: /**
! 403: * Get a string describing feature.
! 404: *
! 405: * @param feature feature to describe
! 406: * @return allocated string describing feature
! 407: */
! 408: char* plugin_feature_get_string(plugin_feature_t *feature);
! 409:
! 410: /**
! 411: * Load a plugin feature using a REGISTER/CALLBACK feature entry.
! 412: *
! 413: * @param plugin plugin providing feature
! 414: * @param feature feature to load
! 415: * @param reg REGISTER/CALLBACK feature entry to use for registration
! 416: */
! 417: bool plugin_feature_load(plugin_t *plugin, plugin_feature_t *feature,
! 418: plugin_feature_t *reg);
! 419:
! 420: /**
! 421: * Unload a plugin feature using a REGISTER/CALLBACK feature entry.
! 422: *
! 423: * @param plugin plugin providing feature
! 424: * @param feature feature to unload
! 425: * @param reg REGISTER/CALLBACK feature entry to use for deregistration
! 426: */
! 427: bool plugin_feature_unload(plugin_t *plugin, plugin_feature_t *feature,
! 428: plugin_feature_t *reg);
! 429:
! 430: #endif /** PLUGIN_FEATURE_H_ @}*/
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>