diff --git a/doc/schema/ildus.schema b/doc/schema/ildus.schema new file mode 100644 index 0000000..5ffeeaf --- /dev/null +++ b/doc/schema/ildus.schema @@ -0,0 +1,11 @@ +# A schema for handling ownership of Ildus DNS records for +# storing DNS zones in LDAP +# +attributetype ( 1.3.6.1.4.1.4203.666.1.4096 NAME 'ildusOwner' + DESC 'Owner of the Ildus dNSDomain2 record' + SUP name ) + +objectclass ( 1.3.6.1.4.1.4203.666.3.4096 NAME 'ildusRecord' + DESC 'A dNSDomain2 record that is updatable via Ildus' + SUP top AUXILIARY + MUST ildusOwner ) diff --git a/lib/ildus/server/backend.rb b/lib/ildus/server/backend.rb index 0e97b6d..237b5c9 100644 --- a/lib/ildus/server/backend.rb +++ b/lib/ildus/server/backend.rb @@ -40,32 +40,73 @@ module Ildus class Basic + attr_reader :config, :user, :pass + def self.inherited(subclass) - type = subclass.to_s.split('::').last.downcase.to_sym + diff = subclass.to_s.split('::') - self.to_s.split('::') + type = diff.to_s.split('::').last.downcase.to_sym Backend.register(type, subclass) end + + def initialize(backend_config) + @config = backend_config + @auth = false + @user = user + @pass = pass + end - def hostnames_of(user) + ################# + # Account methods + + def user=(username) + raise Handler::AlreadyAuthError if @auth + @user = username + end + + def pass=(password) + raise Handler::AlreadyAuthError if @auth + @pass = password + ## STUB + @auth = (password == "foo") + ## + end + + def authenticated? + @auth + end + + def register_account raise Handler::NotImplementedError end - def add_hostname(user) + def unregister_account raise Handler::NotImplementedError end - def remove_hostname(user) + ################# + # Backend methods + + def hostnames raise Handler::NotImplementedError end - def update_hostname(user, host, addr) + def add_hostname(host) raise Handler::NotImplementedError end - def add_alias(user, new_alias, host) + def remove_hostname(host) raise Handler::NotImplementedError end - def remove_alias(user, old_alias, host) + def update_hostname(host, addr) + raise Handler::NotImplementedError + end + + def add_alias(new_alias, host) + raise Handler::NotImplementedError + end + + def remove_alias(old_alias, host) raise Handler::NotImplementedError end diff --git a/lib/ildus/server/backends/ldap.rb b/lib/ildus/server/backends/ldap.rb index 940a2e0..723abd0 100644 --- a/lib/ildus/server/backends/ldap.rb +++ b/lib/ildus/server/backends/ldap.rb @@ -7,9 +7,45 @@ # Software Foundation; either version 2 of the License, or (at your option) # any later version. +require 'ldap' + module Ildus::Server::Backend - class LDAP < Basic - end + class LDAPv3 < Basic -end + def initialize(*args) + super + @ldap = LDAP::Conn.new(config['host']) + @ldap.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3) + @ldap.simple_bind(config['user'], config['pass']) + end + + def hostnames + entries = Hash.new { |h, k| h[k] = [[], []] } + @ldap.search(config['base'], LDAP::LDAP_SCOPE_SUBTREE, + "ildusOwner=#{user}") do |entry| + assoc_dom, a_rr, aaaa_rr, cname_rr = + ["associatedDomain", "aRecord", + "aAAArecord", "cNAMErecord"].map do |attr| + entry.vals(attr) + end + + host = assoc_dom.first.gsub(/\.#{config['domain']}$/, '') + if a_rr + entries[host].first.push(*a_rr) + end + if aaaa_rr + entries[host].first.push(*aaaa_rr) + end + if cname_rr + cname = cname_rr.first.gsub(/\.#{config['domain']}$/, '') + entries[cname].last << host + end + end + + return entries + end # hostnames + + end # class LDAPv3 + +end # module Ildus::Server::Backend diff --git a/lib/ildus/server/handler.rb b/lib/ildus/server/handler.rb index b459410..d490c8b 100644 --- a/lib/ildus/server/handler.rb +++ b/lib/ildus/server/handler.rb @@ -7,7 +7,6 @@ # Software Foundation; either version 2 of the License, or (at your option) # any later version. -require 'ildus/server/account' require 'ildus/server/backend' module Ildus @@ -65,11 +64,13 @@ module Ildus def initialize(server, io) @server = server @io = io - @account = Account.new type = server.config["backend"]["type"] klass = Backend[server.config["backend"]["type"]] raise "backend type `#{type}' not found" if klass.nil? - @backend = klass.new + @backend = klass.new(server.config["backend"]) + rescue => msg + prot_msg 505, msg + raise end def handle_client @@ -140,24 +141,24 @@ module Ildus # Commands methods def user_cmd(username) - @account.user = username + @backend.user = username prot_msg 331 end def pass_cmd(password) - raise SetUserFirstError unless @account.user + raise SetUserFirstError unless @backend.user - @account.pass = password - if @account.authenticated? - prot_msg 230, @account.user + @backend.pass = password + if @backend.authenticated? + prot_msg 230, @backend.user else raise NotAuthError end end def updt_cmd(hostname, addr) - raise NotAuthError unless @account.authenticated? - @backend.update_hostname(@account.user, hostname, addr) + raise NotAuthError unless @backend.authenticated? + @backend.update_hostname(@backend.user, hostname, addr) rescue HostNotFoundError prot_msg 425, hostname rescue RecordNotFoundError @@ -175,11 +176,17 @@ module Ildus end def list_cmd - raise NotAuthError unless @account.authenticated? - user = @account.user - #list = @backend.hostnames_of(user) + raise NotAuthError unless @backend.authenticated? + user = @backend.user + list = @backend.hostnames + h = list.inject(Hash.new) do |memo, (host, info)| + memo[host] = {"addresses" => info.first, "aliases" => info.last} + memo + end + prot_msg_with_body 215, - "Listing of hosts (and aliases) for user #{user}\n" + "Listing of hosts (and aliases) for user #{user}\n" + + h.to_yaml + "\n" end def help_cmd diff --git a/test/tc_handler.rb b/test/tc_handler.rb index c168c0b..3c701f0 100644 --- a/test/tc_handler.rb +++ b/test/tc_handler.rb @@ -1,3 +1,4 @@ +require 'stringio' require 'test/unit' require 'ildus/server' @@ -12,7 +13,7 @@ class TC_HandlerTest < Test::Unit::TestCase assert(@hdl) class << @hdl - attr_reader :account + attr_reader :backend public :handle_command end end @@ -28,28 +29,28 @@ class TC_HandlerTest < Test::Unit::TestCase # Set the user. @hdl.handle_command("user", ["test"]) - assert_equal("test", @hdl.account.user) + assert_equal("test", @hdl.backend.user) # "list" still shouldn't be possible. assert_raises(Server::Handler::NotAuthError) { @hdl.handle_command("list") } # Set a different user. @hdl.handle_command("user", ["test2"]) - assert_equal("test2", @hdl.account.user) + assert_equal("test2", @hdl.backend.user) # Give an incorrect password. assert_raises(Server::Handler::NotAuthError) do @hdl.handle_command("pass", ["secret"]) end - assert_equal("secret", @hdl.account.pass) + assert_equal("secret", @hdl.backend.pass) # Nothing should be raised when setting the password, # we should be authenticated afterwards. assert_nothing_raised do @hdl.handle_command("pass", ["foo"]) end - assert_equal("foo", @hdl.account.pass) - assert(@hdl.account.authenticated?) + assert_equal("foo", @hdl.backend.pass) + assert(@hdl.backend.authenticated?) # "list" should be possible now. assert_nothing_raised do