require 'active_support/secure_random' require 'net/ldap' class SystemDataBackendLdap LDAP_USER_MAP = { :uid => :name, :userpassword => :pass, :uidnumber => :uid, :gidnumber => :gid, :loginshell => :shell, :homedirectory => :home } LDAP_GROUP_MAP = { :cn => :name, :gidnumber => :gid, :memberuid => :members } LDAP_SITE_MAP = {:o => :name} LDAP_MAP = { :User => LDAP_USER_MAP, :Group => LDAP_GROUP_MAP, :Site => LDAP_SITE_MAP } LDAP_FILTER = { :User => Net::LDAP::Filter::eq('objectClass', 'posixAccount'), :Group => Net::LDAP::Filter::eq('objectClass', 'posixGroup'), :Site => Net::LDAP::Filter::eq('objectClass', 'organization') & (~Net::LDAP::Filter::eq('o', 'hosting')), :MailAlias => Net::LDAP::Filter::eq('objectClass', 'mailAlias'), :MailAccount => Net::LDAP::Filter::eq('objectClass', 'mailAccount') } LDAP_OBJECTCLASS = { :User => [ 'account', 'posixAccount', 'shadowAccount' ], :Group => 'posixGroup' } LDAP_LAMBDA_USER = lambda do |entry| entry[:cn] = entry[:uid] entry[:shadowlastchange] = (Time::now.to_i/60/60/24).to_s entry[:replace] += ['shadowreplace'] if entry[:replace] end LDAP_LAMBDA = { :User => LDAP_LAMBDA_USER } def initialize(host, port, baseDn, args={}) @baseDn = baseDn @systemDn = 'o=system,' + @baseDn @hostingDn = 'o=hosting,' + @baseDn @systemDn = args[:systemDn] if args[:systemDn] @hostingDn = args[:hostingDn] if args[:hostingDn] @ldap = Net::LDAP.new(:host => host, :port => port) @ldapData = Hash.new end def load!(kind) @ldapData[kind] = Hash.new if ! @ldapData[kind] @ldapData[kind][:internal] = @ldap.search( :base => ldapBase(kind), :filter => LDAP_FILTER[kind] ) end def load(kind) load!(kind) if ! @ldapData[kind] @ldapData[kind][:external] = @ldapData[kind][:internal].map do |data| map = { :dn => :id } map.merge!(LDAP_MAP[kind]) if LDAP_MAP[kind] ydata = {} data.each do |key,value| ydata.merge!({ map[key] || key => value.size==1?value[0]:value.to_a }) end ydata end if ! @ldapData[kind][:external] @ldapData[kind][:external].each{|ydata| yield ydata} end def update(kind, data) map = {} map.merge!(LDAP_MAP[kind].invert) if LDAP_MAP[kind] entry = Net::LDAP::Entry.new(data[:id]) odata = @ldapData[kind][:external].find{|edata| edata[:id] == data[:id]} data = data.find_all{|key,value| value != odata[key]} data.delete(:id) replace = Array.new data.each do |key,value| key = map[key] if map[key] replace.push(key.to_s) entry[key] = value end if not replace.empty? entry[:changetype] = 'modify' entry[:replace] = replace LDAP_LAMBDA[kind].call(entry) if LDAP_LAMBDA[kind] puts entry.to_ldif else puts 'INFO: no changes' end end private def ldapBase(kind) case(kind) when :User, :Group: @systemDn when :Site, :MailAlias, :MailAccount: @hostingDn end end end