// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace isc; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::util; using namespace std; /// @brief Maximum size of an IPv6 address represented as a text string. /// /// This is 32 hexadecimal characters written in 8 groups of four, plus seven /// colon separators. const size_t ADDRESS6_TEXT_MAX_LEN = 39; /// @brief Maximum length of classes stored in a dhcp4/6_client_classes /// columns. const size_t CLIENT_CLASSES_MAX_LEN = 255; /// @brief Maximum length of the hostname stored in DNS. /// /// This length is restricted by the length of the domain-name carried /// in the Client FQDN %Option (see RFC4702 and RFC4704). const size_t HOSTNAME_MAX_LEN = 255; /// @brief Maximum length of option value. const size_t OPTION_VALUE_MAX_LEN = 4096; /// @brief Maximum length of option value specified in textual format. const size_t OPTION_FORMATTED_VALUE_MAX_LEN = 8192; /// @brief Maximum length of option space name. const size_t OPTION_SPACE_MAX_LEN = 128; /// @brief Maximum length of the server hostname. const size_t SERVER_HOSTNAME_MAX_LEN = 64; /// @brief Maximum length of the boot file name. const size_t BOOT_FILE_NAME_MAX_LEN = 128; /// @brief Numeric value representing last supported identifier. /// /// This value is used to validate whether the identifier type stored in /// a database is within bounds. of supported identifiers. const uint8_t MAX_IDENTIFIER_TYPE = static_cast(Host::LAST_IDENTIFIER_TYPE); namespace isc { namespace dhcp { RadiusHostDataSource:: RadiusHostDataSource(const DatabaseConnection::ParameterMap& parameters) { int res; rh = rc_new(); if (rh == NULL) { isc_throw(isc::Exception, "Failed to initialize Radius client"); } rh = rc_config_init(rh); if (rh == NULL) { isc_throw(isc::Exception, "Failed to initialize Radius client"); } res = rc_add_config(rh, "auth_order", "radius", NULL, 0); if (res != 0) { isc_throw(isc::Exception, "Failed to configure Radius auth_order"); } /* TODO: just define manually the few attributes we need */ res = rc_add_config(rh, "dictionary", "/usr/share/radcli/dictionary", NULL, 0); if (res != 0) { isc_throw(isc::Exception, "Failed to configure Radius dictionary"); } res = rc_add_config(rh, "radius_timeout", "1", NULL, 0); if (res != 0) { isc_throw(isc::Exception, "Failed to configure Radius timeout"); } res = rc_add_config(rh, "radius_retries", "1", NULL, 0); if (res != 0) { isc_throw(isc::Exception, "Failed to configure Radius retries"); } res = rc_add_config(rh, "authserver", "127.0.0.1:1812:mysecret", NULL, 0); if (res != 0) { isc_throw(isc::Exception, "Failed to configure Radius authserver"); } // Test and apply config (this also setups the necessary structures to // send requests to the radius server) res = rc_test_config(rh, "kea"); if (res != 0) { isc_throw(isc::Exception, "Failed to apply radcli configuration"); } // Load dictionary res = rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")); if (res != 0) { isc_throw(isc::Exception, "Failed to read Radius dictionary"); } } RadiusHostDataSource::~RadiusHostDataSource() { } void RadiusHostDataSource::add(const HostPtr& host) { // cannot add a host with radius isc_throw(NotImplemented, "RadiusHostDataSource::add not implemented"); } bool RadiusHostDataSource::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) { // cannot delete hosts with radius isc_throw(NotImplemented, "RadiusHostDataSource::del not implemented"); return false; } bool RadiusHostDataSource::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) { // cannot delete hosts with radius isc_throw(NotImplemented, "RadiusHostDataSource::del4 not implemented"); return false; } bool RadiusHostDataSource::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) { // cannot delete hosts with radius isc_throw(NotImplemented, "RadiusHostDataSource::del6 not implemented"); return false; } ConstHostCollection RadiusHostDataSource::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const { if (duid){ return (getAll(Host::IDENT_DUID, &duid->getDuid()[0], duid->getDuid().size())); } else if (hwaddr) { return (getAll(Host::IDENT_HWADDR, &hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())); } return (ConstHostCollection()); } ConstHostCollection RadiusHostDataSource::getAll(const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) const { ConstHostCollection result; HostPtr host; int res; VALUE_PAIR *send = NULL, *received; if (rc_avpair_add(rh, &send, PW_USER_NAME, identifier_begin, identifier_len, 0) == NULL) isc_throw(isc::Exception, "Failed to set username"); res = rc_auth(rh, 0, send, &received, NULL); if (res == OK_RC) { VALUE_PAIR *vp = received; char name[128]; char value[128]; fprintf(stderr, "\"%s\" RADIUS Authentication OK\n", identifier_begin); /* print the known attributes in the reply */ while(vp != NULL) { if (rc_avpair_tostr(rh, vp, name, sizeof(name), value, sizeof(value)) == 0) { fprintf(stderr, "%s:\t%s\n", name, value); } vp = vp->next; } host.reset(new Host(identifier_begin, identifier_len, identifier_type, SubnetID(), // TODO: set real IP address SubnetID(), asiolink::IOAddress("10.42.42.42"))); result.push_back(host); } else { fprintf(stderr, "\"%s\" RADIUS Authentication failure (RC=%i)\n", identifier_begin, res); } return (result); } ConstHostCollection RadiusHostDataSource::getAll4(const asiolink::IOAddress& address) const { return (ConstHostCollection()); } ConstHostPtr RadiusHostDataSource::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr, const DuidPtr& duid) const { if (hwaddr && duid) { isc_throw(BadValue, "Radius host data source get4() called with both" " hwaddr and duid, only one of them is allowed"); } if (!hwaddr && !duid) { isc_throw(BadValue, "Radius host data source get4() called with " "neither hwaddr or duid specified, one of them is required"); } // Choosing one of the identifiers if (hwaddr) { return (get4(subnet_id, Host::IDENT_HWADDR, &hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())); } else if (duid) { return (get4(subnet_id, Host::IDENT_DUID, &duid->getDuid()[0], duid->getDuid().size())); } return (ConstHostPtr()); } ConstHostPtr RadiusHostDataSource::get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) const { ConstHostCollection collection = getAll(identifier_type, identifier_begin, identifier_len); ConstHostPtr result; if (!collection.empty()) result = *collection.begin(); return (result); } ConstHostPtr RadiusHostDataSource::get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const { // Not relevant for Radius isc_throw(NotImplemented, "RadiusHostDataSource::get4 not implemented"); return (ConstHostPtr()); } ConstHostPtr RadiusHostDataSource::get6(const SubnetID& subnet_id, const DuidPtr& duid, const HWAddrPtr& hwaddr) const { // TODO: libradcli call ConstHostPtr result = NULL; return (result); } ConstHostPtr RadiusHostDataSource::get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) const { // TODO: libradcli call ConstHostPtr result = NULL; return (result); } ConstHostPtr RadiusHostDataSource::get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const { // TODO: libradcli call ConstHostPtr result = NULL; return (result); } ConstHostPtr RadiusHostDataSource::get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const { // TODO: libradcli call ConstHostPtr result = NULL; return (result); } // Miscellaneous database methods. std::string RadiusHostDataSource::getName() const { std::string name = ""; return (name); } std::string RadiusHostDataSource::getDescription() const { return (std::string("Host data source that retrieves host information" "in radius server")); } std::pair RadiusHostDataSource::getVersion() const { // TODO: Not relevant for libradcli ? return std::make_pair(0,0); } void RadiusHostDataSource::commit() { // Not relevant for radius. } void RadiusHostDataSource::rollback() { // Not relevant for radius. } }; // end of isc::dhcp namespace }; // end of isc namespace