Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/proto/ldap/client.rb
Views: 11704
require 'net/ldap'12module Rex3module Proto4module LDAP5# This is a Rex Proto wrapper around the Net::LDAP client which is currently coming from the 'net-ldap' gem.6# The purpose of this wrapper is to provide 'peerhost' and 'peerport' methods to ensure the client interfaces7# are consistent between various session clients.8class Client < Net::LDAP910# @return [Rex::Socket]11attr_reader :socket1213# [Time] The last time an interaction occurred on the connection (for keep-alive purposes)14attr_reader :last_interaction1516# [Mutex] Control access to the connection. One at a time.17attr_reader :connection_use_mutex1819def initialize(args)20@base_dn = args[:base]21@last_interaction = nil22@connection_use_mutex = Mutex.new23super24end2526def register_interaction27@last_interaction = Process.clock_gettime(Process::CLOCK_MONOTONIC)28end2930# @return [Array<String>] LDAP servers naming contexts31def naming_contexts32@naming_contexts ||= search_root_dse[:namingcontexts]33end3435# @return [String] LDAP servers Base DN36def base_dn37@base_dn ||= discover_base_dn38end3940# @return [String, nil] LDAP servers Schema DN, nil if one isn't found41def schema_dn42@schema_dn ||= discover_schema_naming_context43end4445# @return [String] The remote IP address that LDAP is running on46def peerhost47host48end4950# @return [Integer] The remote port that LDAP is running on51def peerport52port53end5455# @return [String] The remote peer information containing IP and port56def peerinfo57"#{peerhost}:#{peerport}"58end5960def use_connection(args)61@connection_use_mutex.synchronize do62return super(args)63ensure64register_interaction65end66end6768# https://github.com/ruby-ldap/ruby-net-ldap/issues/1169# We want to keep the ldap connection open to use later70# but there's no built in way within the `Net::LDAP` library to do that71# so we're adding this function to do it instead72# @param connect_opts [Hash] Options for the LDAP connection.73def self._open(connect_opts)74client = new(connect_opts)75client._open76end7778# https://github.com/ruby-ldap/ruby-net-ldap/issues/1179def _open80raise Net::LDAP::AlreadyOpenedError, 'Open already in progress' if @open_connection8182instrument 'open.net_ldap' do |payload|83@open_connection = new_connection84@socket = @open_connection.socket85payload[:connection] = @open_connection86payload[:bind] = @result = @open_connection.bind(@auth)87register_interaction88return self89end90end9192def discover_schema_naming_context93result = search(base: '', attributes: [:schemanamingcontext], scope: Net::LDAP::SearchScope_BaseObject)94if result.first && !result.first[:schemanamingcontext].empty?95schema_dn = result.first[:schemanamingcontext].first96ilog("#{peerinfo} Discovered Schema DN: #{schema_dn}")97return schema_dn98end99wlog("#{peerinfo} Could not discover Schema DN")100nil101end102103def discover_base_dn104unless naming_contexts105elog("#{peerinfo} Base DN cannot be determined, no naming contexts available")106return107end108109# NOTE: Find the first entry that starts with `DC=` as this will likely be the base DN.110result = naming_contexts.select { |context| context =~ /^([Dd][Cc]=[A-Za-z0-9-]+,?)+$/ }111.reject { |context| context =~ /(Configuration)|(Schema)|(ForestDnsZones)/ }112if result.blank?113elog("#{peerinfo} A base DN matching the expected format could not be found!")114return115end116base_dn = result[0]117118dlog("#{peerinfo} Discovered base DN: #{base_dn}")119base_dn120end121122# Monkeypatch upstream library to support the extended Whoami request. Delete123# this after https://github.com/ruby-ldap/ruby-net-ldap/pull/425 is landed.124# This is not the only occurrence of a patch for this functionality.125def ldapwhoami(args = {})126instrument "ldapwhoami.net_ldap", args do |payload|127@result = use_connection(args, &:ldapwhoami)128@result.success? ? @result.extended_response : nil129end130end131end132end133end134end135136137