File Manager
Viewing File: sid.rb
#
# Author:: John Keiser (<jkeiser@chef.io>)
# Copyright:: Copyright (c) Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require_relative "../security"
require_relative "../api/net"
require_relative "../api/error"
require "wmi-lite/wmi"
class Chef
module ReservedNames::Win32
class Security
class SID
include Chef::ReservedNames::Win32::API::Net
include Chef::ReservedNames::Win32::API::Error
class << self
include Chef::ReservedNames::Win32::API::Net
include Chef::ReservedNames::Win32::API::Error
end
def initialize(pointer, owner = nil)
@pointer = pointer
# Keep a reference to the actual owner of this memory so we don't get freed
@owner = owner
end
def self.from_account(name)
domain, sid, use = Chef::ReservedNames::Win32::Security.lookup_account_name(name)
sid
end
def self.from_string_sid(string_sid)
Chef::ReservedNames::Win32::Security.convert_string_sid_to_sid(string_sid)
end
def ==(other)
!other.nil? && Chef::ReservedNames::Win32::Security.equal_sid(self, other)
end
attr_reader :pointer
def account
Chef::ReservedNames::Win32::Security.lookup_account_sid(self)
end
def account_simple_name
domain, name, use = account
name
end
def account_name
domain, name, use = account
(!domain.nil? && domain.length > 0) ? "#{domain}\\#{name}" : name
end
def size
Chef::ReservedNames::Win32::Security.get_length_sid(self)
end
def to_s
Chef::ReservedNames::Win32::Security.convert_sid_to_string_sid(self)
end
def valid?
Chef::ReservedNames::Win32::Security.is_valid_sid(self)
end
# Well-known SIDs
def self.Null
SID.from_string_sid("S-1-0")
end
def self.Nobody
SID.from_string_sid("S-1-0-0")
end
def self.World
SID.from_string_sid("S-1-1")
end
def self.Everyone
SID.from_string_sid("S-1-1-0")
end
def self.Local
SID.from_string_sid("S-1-2")
end
def self.Creator
SID.from_string_sid("S-1-3")
end
def self.CreatorOwner
SID.from_string_sid("S-1-3-0")
end
def self.CreatorGroup
SID.from_string_sid("S-1-3-1")
end
def self.CreatorOwnerServer
SID.from_string_sid("S-1-3-2")
end
def self.CreatorGroupServer
SID.from_string_sid("S-1-3-3")
end
def self.NonUnique
SID.from_string_sid("S-1-4")
end
def self.Nt
SID.from_string_sid("S-1-5")
end
def self.Dialup
SID.from_string_sid("S-1-5-1")
end
def self.Network
SID.from_string_sid("S-1-5-2")
end
def self.Batch
SID.from_string_sid("S-1-5-3")
end
def self.Interactive
SID.from_string_sid("S-1-5-4")
end
def self.Service
SID.from_string_sid("S-1-5-6")
end
def self.Anonymous
SID.from_string_sid("S-1-5-7")
end
def self.Proxy
SID.from_string_sid("S-1-5-8")
end
def self.EnterpriseDomainControllers
SID.from_string_sid("S-1-5-9")
end
def self.PrincipalSelf
SID.from_string_sid("S-1-5-10")
end
def self.AuthenticatedUsers
SID.from_string_sid("S-1-5-11")
end
def self.RestrictedCode
SID.from_string_sid("S-1-5-12")
end
def self.TerminalServerUsers
SID.from_string_sid("S-1-5-13")
end
def self.LocalSystem
SID.from_string_sid("S-1-5-18")
end
def self.NtLocal
SID.from_string_sid("S-1-5-19")
end
def self.NtNetwork
SID.from_string_sid("S-1-5-20")
end
def self.BuiltinAdministrators
SID.from_string_sid("S-1-5-32-544")
end
def self.BuiltinUsers
SID.from_string_sid("S-1-5-32-545")
end
def self.Guests
SID.from_string_sid("S-1-5-32-546")
end
def self.PowerUsers
SID.from_string_sid("S-1-5-32-547")
end
def self.AccountOperators
SID.from_string_sid("S-1-5-32-548")
end
def self.ServerOperators
SID.from_string_sid("S-1-5-32-549")
end
def self.PrintOperators
SID.from_string_sid("S-1-5-32-550")
end
def self.BackupOperators
SID.from_string_sid("S-1-5-32-551")
end
def self.Replicators
SID.from_string_sid("S-1-5-32-552")
end
def self.Administrators
SID.from_string_sid("S-1-5-32-544")
end
def self.None
SID.from_account("#{::ENV["COMPUTERNAME"]}\\None")
end
def self.Administrator
SID.from_account("#{::ENV["COMPUTERNAME"]}\\#{SID.admin_account_name}")
end
def self.Guest
SID.from_account("#{::ENV["COMPUTERNAME"]}\\Guest")
end
def self.current_user
SID.from_account("#{::ENV["USERDOMAIN"]}\\#{::ENV["USERNAME"]}")
end
SERVICE_ACCOUNT_USERS = [self.LocalSystem,
self.NtLocal,
self.NtNetwork].flat_map do |user_type|
[user_type.account_simple_name.upcase,
user_type.account_name.upcase]
end.freeze
BUILT_IN_GROUPS = [self.BuiltinAdministrators,
self.BuiltinUsers, self.Guests].flat_map do |user_type|
[user_type.account_simple_name.upcase,
user_type.account_name.upcase]
end.freeze
SYSTEM_USER = SERVICE_ACCOUNT_USERS + BUILT_IN_GROUPS
# Check if the user belongs to service accounts category
#
# @return [Boolean] True or False
#
def self.service_account_user?(user)
SERVICE_ACCOUNT_USERS.include?(user.to_s.upcase)
end
# Check if the user is in builtin system group
#
# @return [Boolean] True or False
#
def self.group_user?(user)
BUILT_IN_GROUPS.include?(user.to_s.upcase)
end
# Check if the user belongs to system users category
#
# @return [Boolean] True or False
#
def self.system_user?(user)
SYSTEM_USER.include?(user.to_s.upcase)
end
# See https://technet.microsoft.com/en-us/library/cc961992.aspx
# In practice, this is SID.Administrators if the current_user is an admin (even if not
# running elevated), and is current_user otherwise.
def self.default_security_object_owner
token = Chef::ReservedNames::Win32::Security.open_current_process_token
Chef::ReservedNames::Win32::Security.get_token_information_owner(token)
end
# See https://technet.microsoft.com/en-us/library/cc961996.aspx
# In practice, this seems to be SID.current_user for Microsoft Accounts, the current
# user's Domain Users group for domain accounts, and SID.None otherwise.
def self.default_security_object_group
token = Chef::ReservedNames::Win32::Security.open_current_process_token
Chef::ReservedNames::Win32::Security.get_token_information_primary_group(token)
end
def self.admin_account_name
@admin_account_name ||= begin
admin_account_name = nil
# Call NetUserEnum to enumerate the users without hitting network
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa370652(v=vs.85).aspx
servername = nil # We are querying the local server
level = 3 # We want USER_INFO_3 structure which contains the SID
filter = FILTER_NORMAL_ACCOUNT # Only query the user accounts
bufptr = FFI::MemoryPointer.new(:pointer) # Buffer which will receive the data
prefmaxlen = MAX_PREFERRED_LENGTH # Let the system allocate the needed amount of memory
entriesread = FFI::Buffer.new(:long).write_long(0)
totalentries = FFI::Buffer.new(:long).write_long(0)
resume_handle = FFI::Buffer.new(:long).write_long(0)
status = ERROR_MORE_DATA
while status == ERROR_MORE_DATA
status = NetUserEnum(servername, level, filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle)
if status == NERR_Success || status == ERROR_MORE_DATA
Array.new(entriesread.read_long) do |i|
user_info = USER_INFO_3.new(bufptr.read_pointer + i * USER_INFO_3.size)
# Check if the account is the Administrator account
# RID for the Administrator account is always 500 and it's privilege is set to USER_PRIV_ADMIN
if user_info[:usri3_user_id] == 500 && user_info[:usri3_priv] == 2 # USER_PRIV_ADMIN (2) - Administrator
admin_account_name = user_info[:usri3_name].read_wstring
break
end
end
# Free the memory allocated by the system
NetApiBufferFree(bufptr.read_pointer)
end
end
raise "Can not determine the administrator account name." if admin_account_name.nil?
admin_account_name
end
end
end
end
end
end