File: windows_adsi.rb

package info (click to toggle)
puppet-agent 7.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 19,092 kB
  • sloc: ruby: 245,074; sh: 456; makefile: 38; xml: 33
file content (172 lines) | stat: -rw-r--r-- 4,746 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
require_relative '../../../puppet/util/windows'

Puppet::Type.type(:user).provide :windows_adsi do
  desc "Local user management for Windows."

  defaultfor :operatingsystem => :windows
  confine    :operatingsystem => :windows

  has_features :manages_homedir, :manages_passwords, :manages_roles

  def initialize(value={})
    super(value)
    @deleted = false
  end

  def user
    @user ||= Puppet::Util::Windows::ADSI::User.new(@resource[:name])
  end

  def roles
    Puppet::Util::Windows::User::get_rights(@resource[:name])
  end

  def roles=(value)
    current = roles.split(',')
    should  = value.split(',')

    add_list = should - current
    Puppet::Util::Windows::User::set_rights(@resource[:name], add_list) unless add_list.empty?

    if @resource[:role_membership] == :inclusive
      remove_list = current - should
      Puppet::Util::Windows::User::remove_rights(@resource[:name], remove_list) unless remove_list.empty?
    end
  end

  def groups
    @groups ||= Puppet::Util::Windows::ADSI::Group.name_sid_hash(user.groups)
    @groups.keys
  end

  def groups=(groups)
    user.set_groups(groups, @resource[:membership] == :minimum)
  end

  def groups_insync?(current, should)
    return false unless current

    # By comparing account SIDs we don't have to worry about case
    # sensitivity, or canonicalization of account names.

    # Cannot use munge of the group property to canonicalize @should
    # since the default array_matching comparison is not commutative

    # dupes automatically weeded out when hashes built
    current_groups = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
    specified_groups = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)

    current_sids = current_groups.keys.to_a
    specified_sids = specified_groups.keys.to_a

    if @resource[:membership] == :inclusive
      current_sids.sort == specified_sids.sort
    else
      (specified_sids & current_sids) == specified_sids
    end
  end

  def groups_to_s(groups)
    return '' if groups.nil? || !groups.kind_of?(Array)
    groups = groups.map do |group_name|
      sid = Puppet::Util::Windows::SID.name_to_principal(group_name)
      if sid.account =~ /\\/
        account, _ = Puppet::Util::Windows::ADSI::Group.parse_name(sid.account)
      else
        account = sid.account
      end
      resource.debug("#{sid.domain}\\#{account} (#{sid.sid})")
      "#{sid.domain}\\#{account}"
    end
    return groups.join(',')
  end

  def create
    @user = Puppet::Util::Windows::ADSI::User.create(@resource[:name])
    @user.password = @resource[:password]
    @user.commit

    [:comment, :home, :groups].each do |prop|
      send("#{prop}=", @resource[prop]) if @resource[prop]
    end

    if @resource.managehome?
      Puppet::Util::Windows::User.load_profile(@resource[:name], @resource[:password])
    end
  end

  def exists?
    Puppet::Util::Windows::ADSI::User.exists?(@resource[:name])
  end

  def delete
    # lookup sid before we delete account
    sid = uid if @resource.managehome?

    Puppet::Util::Windows::ADSI::User.delete(@resource[:name])

    if sid
      Puppet::Util::Windows::ADSI::UserProfile.delete(sid)
    end

    @deleted = true
  end

  # Only flush if we created or modified a user, not deleted
  def flush
    @user.commit if @user && !@deleted
  end

  def comment
    user['Description']
  end

  def comment=(value)
    user['Description'] = value
  end

  def home
    user['HomeDirectory']
  end

  def home=(value)
    user['HomeDirectory'] = value
  end

  def password
    # avoid a LogonUserW style password check when the resource is not yet
    # populated with a password (as is the case with `puppet resource user`)
    return nil if @resource[:password].nil?
    user.password_is?( @resource[:password] ) ? @resource[:password] : nil
  end

  def password=(value)
    if user.disabled?
      info _("The user account '%s' is disabled; The password will still be changed" % @resource[:name])
    elsif user.locked_out?
      info _("The user account '%s' is locked out; The password will still be changed" % @resource[:name])
    elsif user.expired?
      info _("The user account '%s' is expired; The password will still be changed" % @resource[:name])
    end
    user.password = value
  end

  def uid
    Puppet::Util::Windows::SID.name_to_sid(@resource[:name])
  end

  def uid=(value)
    fail "uid is read-only"
  end

  [:gid, :shell].each do |prop|
    define_method(prop) { nil }
    define_method("#{prop}=") do |v|
      fail "No support for managing property #{prop} of user #{@resource[:name]} on Windows"
    end
  end

  def self.instances
    Puppet::Util::Windows::ADSI::User.map { |u| new(:ensure => :present, :name => u.name) }
  end
end