summaryrefslogtreecommitdiffstats
path: root/lib/puppet/server
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/server')
-rwxr-xr-xlib/puppet/server/authstore.rb224
1 files changed, 224 insertions, 0 deletions
diff --git a/lib/puppet/server/authstore.rb b/lib/puppet/server/authstore.rb
new file mode 100755
index 000000000..966bc8372
--- /dev/null
+++ b/lib/puppet/server/authstore.rb
@@ -0,0 +1,224 @@
+#!/usr/bin/ruby -w
+
+#--------------------
+# standard module for determining whether a given hostname or IP has access to
+# the requested resource
+#
+# $Id$
+
+require 'ipaddr'
+
+module Puppet
+class Server
+ class AuthStoreError < Puppet::Error; end
+ class AuthorizationError < Puppet::Error; end
+
+ class AuthStore
+ ORDER = {
+ :ip => [:ip],
+ :name => [:hostname, :domain]
+ }
+
+ def allow(pattern)
+ # a simple way to allow anyone at all to connect
+ if pattern == "*"
+ @globalallow = true
+ else
+ store(pattern, @allow)
+ end
+ end
+
+ def allowed?(name, ip)
+ if name or ip
+ unless name and ip
+ raise Puppet::DevError, "Name and IP must be passed to 'allowed?'"
+ end
+ # else, we're networked and such
+ else
+ # we're local
+ return true
+ end
+
+ # yay insecure overrides
+ if @globalallow
+ return true
+ end
+
+ value = nil
+ ORDER.each { |nametype, array|
+ if nametype == :ip
+ value = IPAddr.new(ip)
+ else
+ value = name.split(".").reverse
+ end
+
+ array.each { |type|
+ [[@deny, false], [@allow, true]].each { |ary|
+ hash, retval = ary
+ if hash.include?(type)
+ hash[type].each { |pattern|
+ if match?(nametype, value, pattern)
+ return retval
+ end
+ }
+ end
+ }
+ }
+ }
+
+ # default to false
+ return false
+ end
+
+ def deny(pattern)
+ store(pattern, @deny)
+ end
+
+ def initialize
+ @globalallow = nil
+ @allow = Hash.new { |hash, key|
+ hash[key] = []
+ }
+ @deny = Hash.new { |hash, key|
+ hash[key] = []
+ }
+ end
+
+ private
+
+ def match?(nametype, value, pattern)
+ if value == pattern # simplest shortcut
+ return true
+ end
+
+ case nametype
+ when :ip: matchip?(value, pattern)
+ when :name: matchname?(value, pattern)
+ else
+ raise Puppet::DevError, "Invalid match type %s" % nametype
+ end
+ end
+
+ def matchip?(value, pattern)
+ # we're just using builtin stuff for this, thankfully
+ if pattern.include?(value)
+ return true
+ else
+ return false
+ end
+ end
+
+ def matchname?(value, pattern)
+ # yay, horribly inefficient
+ if pattern[-1] != '*' # the pattern has no metachars and is not equal
+ # thus, no match
+ #Puppet.info "%s is not equal with no * in %s" % [value, pattern]
+ return false
+ else
+ # we know the last field of the pattern is '*'
+ # if everything up to that doesn't match, we're definitely false
+ if pattern[0..-2] != value[0..pattern.length-2]
+ #Puppet.notice "subpatterns didn't match; %s vs %s" %
+ # [pattern[0..-2], value[0..pattern.length-2]]
+ return false
+ end
+
+ case value.length <=> pattern.length
+ when -1: # value is shorter than pattern
+ if pattern.length - value.length == 1
+ # only ever allowed when the value is the domain of a
+ # splatted pattern
+ #Puppet.info "allowing splatted domain %s" % [value]
+ return true
+ else
+ return false
+ end
+ when 0: # value is the same length as pattern
+ if pattern[-1] == "*"
+ #Puppet.notice "same length with *"
+ return true
+ else
+ return false
+ end
+ when 1: # value is longer than pattern
+ # at this point we've already verified that everything up to
+ # the '*' in the pattern matches, so we are true
+ return true
+ end
+ end
+ end
+
+ def store(pattern, hash)
+ type, value = type(pattern)
+
+ if type and value
+ # this won't work once we get beyond simple stuff...
+ hash[type] << value
+ else
+ raise AuthStoreError, "Invalid pattern %s" % pattern
+ end
+ end
+
+ def type(pattern)
+ type = value = nil
+ case pattern
+ when /^(\d+\.){3}\d+$/:
+ type = :ip
+ begin
+ value = IPAddr.new(pattern)
+ rescue ArgumentError => detail
+ raise AuthStoreError, "Invalid IP address pattern %s" % pattern
+ end
+ when /^(\d+\.){3}\d+\/(\d+)$/:
+ mask = Integer($2)
+ if mask < 1 or mask > 32
+ raise AuthStoreError, "Invalid IP mask %s" % mask
+ end
+ type = :ip
+ begin
+ value = IPAddr.new(pattern)
+ rescue ArgumentError => detail
+ raise AuthStoreError, "Invalid IP address pattern %s" % pattern
+ end
+ when /^(\d+\.){1,3}\*$/: # an ip address with a '*' at the end
+ type = :ip
+ match = $1
+ match.sub!(".", '')
+ ary = pattern.split(".")
+
+ mask = case ary.index(match)
+ when 0: 8
+ when 1: 16
+ when 2: 24
+ else
+ raise AuthStoreError, "Invalid IP pattern %s" % pattern
+ end
+
+ ary.pop
+ while ary.length < 4
+ ary.push("0")
+ end
+
+ begin
+ value = IPAddr.new(ary.join(".") + "/" + mask.to_s)
+ rescue ArgumentError => detail
+ raise AuthStoreError, "Invalid IP address pattern %s" % pattern
+ end
+ when /^[\d.]+$/: # necessary so incomplete IP addresses can't look
+ # like hostnames
+ raise AuthStoreError, "Invalid IP address pattern %s" % pattern
+ when /^([a-zA-Z][-\w]*\.)+[-\w]+$/: # a full hostname
+ type = :hostname
+ value = pattern.split(".").reverse
+ when /^\*\.([a-zA-Z][-\w]*\.)+[-\w]+$/: # this doesn't match TLDs
+ type = :domain
+ value = pattern.split(".").reverse
+ else
+ raise AuthStoreError, "Invalid pattern %s" % pattern
+ end
+
+ return [type, value]
+ end
+ end
+end
+end