PageRenderTime 60ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/puppet/util/adsi.rb

https://github.com/glarizza/puppet-1
Ruby | 294 lines | 227 code | 58 blank | 9 comment | 9 complexity | 3aeb0e842e894418304c1afdf7d61d67 MD5 | raw file
  1. module Puppet::Util::ADSI
  2. class << self
  3. def connectable?(uri)
  4. begin
  5. !! connect(uri)
  6. rescue
  7. false
  8. end
  9. end
  10. def connect(uri)
  11. begin
  12. WIN32OLE.connect(uri)
  13. rescue Exception => e
  14. raise Puppet::Error.new( "ADSI connection error: #{e}" )
  15. end
  16. end
  17. def create(name, resource_type)
  18. Puppet::Util::ADSI.connect(computer_uri).Create(resource_type, name)
  19. end
  20. def delete(name, resource_type)
  21. Puppet::Util::ADSI.connect(computer_uri).Delete(resource_type, name)
  22. end
  23. def computer_name
  24. unless @computer_name
  25. buf = " " * 128
  26. Win32API.new('kernel32', 'GetComputerName', ['P','P'], 'I').call(buf, buf.length.to_s)
  27. @computer_name = buf.unpack("A*")
  28. end
  29. @computer_name
  30. end
  31. def computer_uri
  32. "WinNT://#{computer_name}"
  33. end
  34. def wmi_resource_uri( host = '.' )
  35. "winmgmts:{impersonationLevel=impersonate}!//#{host}/root/cimv2"
  36. end
  37. def uri(resource_name, resource_type)
  38. "#{computer_uri}/#{resource_name},#{resource_type}"
  39. end
  40. def execquery(query)
  41. connect(wmi_resource_uri).execquery(query)
  42. end
  43. def sid_for_account(name)
  44. sid = nil
  45. if name =~ /\\/
  46. domain, name = name.split('\\', 2)
  47. query = "SELECT Sid from Win32_Account WHERE Name = '#{name}' AND Domain = '#{domain}' AND LocalAccount = true"
  48. else
  49. query = "SELECT Sid from Win32_Account WHERE Name = '#{name}' AND LocalAccount = true"
  50. end
  51. execquery(query).each { |u| sid ||= u.Sid }
  52. sid
  53. end
  54. end
  55. class User
  56. extend Enumerable
  57. attr_accessor :native_user
  58. attr_reader :name
  59. def initialize(name, native_user = nil)
  60. @name = name
  61. @native_user = native_user
  62. end
  63. def native_user
  64. @native_user ||= Puppet::Util::ADSI.connect(uri)
  65. end
  66. def self.uri(name)
  67. Puppet::Util::ADSI.uri(name, 'user')
  68. end
  69. def uri
  70. self.class.uri(name)
  71. end
  72. def self.logon(name, password)
  73. fLOGON32_LOGON_NETWORK = 3
  74. fLOGON32_PROVIDER_DEFAULT = 0
  75. logon_user = Win32API.new("advapi32", "LogonUser", ['P', 'P', 'P', 'L', 'L', 'P'], 'L')
  76. close_handle = Win32API.new("kernel32", "CloseHandle", ['P'], 'V')
  77. token = ' ' * 4
  78. if logon_user.call(name, "", password, fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, token) != 0
  79. close_handle.call(token.unpack('L')[0])
  80. true
  81. else
  82. false
  83. end
  84. end
  85. def [](attribute)
  86. native_user.Get(attribute)
  87. end
  88. def []=(attribute, value)
  89. native_user.Put(attribute, value)
  90. end
  91. def commit
  92. begin
  93. native_user.SetInfo unless native_user.nil?
  94. rescue Exception => e
  95. raise Puppet::Error.new( "User update failed: #{e}" )
  96. end
  97. self
  98. end
  99. def password_is?(password)
  100. self.class.logon(name, password)
  101. end
  102. def add_flag(flag_name, value)
  103. flag = native_user.Get(flag_name) rescue 0
  104. native_user.Put(flag_name, flag | value)
  105. commit
  106. end
  107. def password=(password)
  108. native_user.SetPassword(password)
  109. commit
  110. fADS_UF_DONT_EXPIRE_PASSWD = 0x10000
  111. add_flag("UserFlags", fADS_UF_DONT_EXPIRE_PASSWD)
  112. end
  113. def groups
  114. # WIN32OLE objects aren't enumerable, so no map
  115. groups = []
  116. native_user.Groups.each {|g| groups << g.Name} rescue nil
  117. groups
  118. end
  119. def add_to_groups(*group_names)
  120. group_names.each do |group_name|
  121. Puppet::Util::ADSI::Group.new(group_name).add_member(@name)
  122. end
  123. end
  124. alias add_to_group add_to_groups
  125. def remove_from_groups(*group_names)
  126. group_names.each do |group_name|
  127. Puppet::Util::ADSI::Group.new(group_name).remove_member(@name)
  128. end
  129. end
  130. alias remove_from_group remove_from_groups
  131. def set_groups(desired_groups, minimum = true)
  132. return if desired_groups.nil? or desired_groups.empty?
  133. desired_groups = desired_groups.split(',').map(&:strip)
  134. current_groups = self.groups
  135. # First we add the user to all the groups it should be in but isn't
  136. groups_to_add = desired_groups - current_groups
  137. add_to_groups(*groups_to_add)
  138. # Then we remove the user from all groups it is in but shouldn't be, if
  139. # that's been requested
  140. groups_to_remove = current_groups - desired_groups
  141. remove_from_groups(*groups_to_remove) unless minimum
  142. end
  143. def self.create(name)
  144. # Windows error 1379: The specified local group already exists.
  145. raise Puppet::Error.new( "Cannot create user if group '#{name}' exists." ) if Puppet::Util::ADSI::Group.exists? name
  146. new(name, Puppet::Util::ADSI.create(name, 'user'))
  147. end
  148. def self.exists?(name)
  149. Puppet::Util::ADSI::connectable?(User.uri(name))
  150. end
  151. def self.delete(name)
  152. Puppet::Util::ADSI.delete(name, 'user')
  153. end
  154. def self.each(&block)
  155. wql = Puppet::Util::ADSI.execquery("select * from win32_useraccount")
  156. users = []
  157. wql.each do |u|
  158. users << new(u.name, u)
  159. end
  160. users.each(&block)
  161. end
  162. end
  163. class Group
  164. extend Enumerable
  165. attr_accessor :native_group
  166. attr_reader :name
  167. def initialize(name, native_group = nil)
  168. @name = name
  169. @native_group = native_group
  170. end
  171. def uri
  172. self.class.uri(name)
  173. end
  174. def self.uri(name)
  175. Puppet::Util::ADSI.uri(name, 'group')
  176. end
  177. def native_group
  178. @native_group ||= Puppet::Util::ADSI.connect(uri)
  179. end
  180. def commit
  181. begin
  182. native_group.SetInfo unless native_group.nil?
  183. rescue Exception => e
  184. raise Puppet::Error.new( "Group update failed: #{e}" )
  185. end
  186. self
  187. end
  188. def add_members(*names)
  189. names.each do |name|
  190. native_group.Add(Puppet::Util::ADSI::User.uri(name))
  191. end
  192. end
  193. alias add_member add_members
  194. def remove_members(*names)
  195. names.each do |name|
  196. native_group.Remove(Puppet::Util::ADSI::User.uri(name))
  197. end
  198. end
  199. alias remove_member remove_members
  200. def members
  201. # WIN32OLE objects aren't enumerable, so no map
  202. members = []
  203. native_group.Members.each {|m| members << m.Name}
  204. members
  205. end
  206. def set_members(desired_members)
  207. return if desired_members.nil? or desired_members.empty?
  208. current_members = self.members
  209. # First we add all missing members
  210. members_to_add = desired_members - current_members
  211. add_members(*members_to_add)
  212. # Then we remove all extra members
  213. members_to_remove = current_members - desired_members
  214. remove_members(*members_to_remove)
  215. end
  216. def self.create(name)
  217. # Windows error 2224: The account already exists.
  218. raise Puppet::Error.new( "Cannot create group if user '#{name}' exists." ) if Puppet::Util::ADSI::User.exists? name
  219. new(name, Puppet::Util::ADSI.create(name, 'group'))
  220. end
  221. def self.exists?(name)
  222. Puppet::Util::ADSI.connectable?(Group.uri(name))
  223. end
  224. def self.delete(name)
  225. Puppet::Util::ADSI.delete(name, 'group')
  226. end
  227. def self.each(&block)
  228. wql = Puppet::Util::ADSI.execquery( "select * from win32_group" )
  229. groups = []
  230. wql.each do |g|
  231. groups << new(g.name, g)
  232. end
  233. groups.each(&block)
  234. end
  235. end
  236. end