class Sys::Admin
The Admin
class provides a unified, cross platform replacement for the Etc module.
Constants
- BUF_MAX
:no-doc:
- HKEY
- SidTypeAlias
- SidTypeComputer
- SidTypeDeletedAccount
- SidTypeDomain
- SidTypeGroup
- SidTypeInvalid
- SidTypeUnknown
- SidTypeUser
- SidTypeWellKnownGroup
- VERSION
The version of the sys-admin library.
Public Class Methods
Create a new group
using options
. If no domain option is specified then a local group is created instead.
Examples:
# Create a local group with no options Sys::Admin.add_group(:name => 'Dudes') # Create a local group with options Sys::Admin.add_group(:name => 'Dudes', :description => 'Boys') # Create a group on a specific domain Sys::Admin.add_group( :name => 'Ladies', :domain => 'XYZ', :description => 'Girls' )
# File lib/windows/sys/admin.rb, line 254 def self.add_group(options = {}) options = munge_options(options) group = options.delete(:name) or raise ArgumentError, 'No name given' domain = options[:domain] if domain.nil? domain = Socket.gethostname moniker = "WinNT://#{domain},Computer" else moniker = "WinNT://#{domain}" end begin adsi = WIN32OLE.connect(moniker) group = adsi.create('group', group) group.setinfo configure_group(options) unless options.empty? rescue WIN32OLERuntimeError => err raise Error, err end end
Adds user
to group
on the specified domain
, or the localhost if no domain is specified.
# File lib/windows/sys/admin.rb, line 280 def self.add_group_member(user, group, domain=nil) domain ||= Socket.gethostname adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group") adsi.Add("WinNT://#{domain}/#{user}") rescue WIN32OLERuntimeError => err raise Error, err end
Creates the given user
. If no domain option is specified, then it defaults to your local host, i.e. a local account is created.
Any options provided are treated as IADsUser interface methods and are called before SetInfo is finally called.
Examples:
# Create a local user with no options Sys::Admin.add_user(:name => 'asmith') # Create a local user with options Sys::Admin.add_user( :name => 'asmith', :description => 'Really cool guy', :password => 'abc123' ) # Create a user on a specific domain Sys::Admin.add_user( :name => 'asmith', :domain => 'XX', :fullname => 'Al Smith' )
# File lib/windows/sys/admin.rb, line 132 def self.add_user(options = {}) options = munge_options(options) name = options.delete(:name) or raise ArgumentError, 'No user given' domain = options[:domain] if domain.nil? domain = Socket.gethostname moniker = "WinNT://#{domain},Computer" else moniker = "WinNT://#{domain}" end begin adsi = WIN32OLE.connect(moniker) user = adsi.create('user', name) options.each{ |option, value| if option.to_s == 'password' user.setpassword(value) else user.put(option.to_s, value) end } user.setinfo rescue WIN32OLERuntimeError => err raise Error, err end end
Configures the group
using options
. If no domain option is specified then your local host is used, i.e. you are configuring a local group.
See tinyurl.com/cjkzl for a list of valid options.
Examples:
# Configure a local group. Sys::Admin.configure_group(:name => 'Abba', :description => 'Swedish') # Configure a group on a specific domain. Sys::Admin.configure_group( :name => 'Web Team', :domain => 'Foo', :description => 'Web programming cowboys' )
# File lib/windows/sys/admin.rb, line 317 def self.configure_group(options = {}) options = munge_options(options) group = options.delete(:name) or raise ArgumentError, 'No name given' domain = options[:domain] || Socket.gethostname begin adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group") options.each{ |option, value| adsi.put(option.to_s, value) } adsi.setinfo rescue WIN32OLERuntimeError => err raise Error, err end end
Configures the user
using options
. If no domain option is specified then your local host is used, i.e. you are configuring a local user account.
See tinyurl.com/3hjv9 for a list of valid options.
In the case of a password change, pass a two element array as the old value and new value.
Examples:
# Configure a local user Sys::Admin.configure_user( :name => 'djberge', :description => 'Awesome' ) # Change the password Sys::Admin.configure_user( :name => 'asmith', :password => 'new_password' ) # Configure a user on a specific domain Sys::Admin.configure_user( :name => 'jsmrz', :domain => 'XX', :firstname => 'Jo' )
# File lib/windows/sys/admin.rb, line 193 def self.configure_user(options = {}) options = munge_options(options) name = options.delete(:name) or raise ArgumentError, 'No name given' domain = options[:domain] || Socket.gethostname begin adsi = WIN32OLE.connect("WinNT://#{domain}/#{name},user") options.each{ |option, value| if option.to_s == 'password' adsi.setpassword(value) else adsi.put(option.to_s, value) end } adsi.setinfo rescue WIN32OLERuntimeError => err raise Error, err end end
Delete the group
from domain
. If no domain is specified, then you are deleting a local group.
# File lib/windows/sys/admin.rb, line 335 def self.delete_group(group, domain = nil) if domain.nil? domain = Socket.gethostname moniker = "WinNT://#{domain},Computer" else moniker = "WinNT://#{domain}" end begin adsi = WIN32OLE.connect(moniker) adsi.delete('group', group) rescue WIN32OLERuntimeError => err raise Error, err end end
Deletes the given user
on domain
. If no domain is specified, then it defaults to your local host, i.e. a local account is deleted.
# File lib/windows/sys/admin.rb, line 220 def self.delete_user(user, domain = nil) if domain.nil? domain = Socket.gethostname moniker = "WinNT://#{domain},Computer" else moniker = "WinNT://#{domain}" end begin adsi = WIN32OLE.connect(moniker) adsi.delete('user', user) rescue WIN32OLERuntimeError => err raise Error, err end end
Returns a Group
object for the given name or uid. Raises an error if a group cannot be found.
Examples:
Sys::Admin.get_group('admin') Sys::Admin.get_group(101)
# File lib/bsd/sys/admin.rb, line 127 def self.get_group(gid) size = 1024 buf = FFI::MemoryPointer.new(:char, size) pbuf = FFI::MemoryPointer.new(PasswdStruct) temp = GroupStruct.new begin if gid.is_a?(String) val = getgrnam_r(gid, temp, buf, buf.size, pbuf) fun = 'getgrnam_r' else val = getgrgid_r(gid, temp, buf, buf.size, pbuf) fun = 'getgrgid_r' end raise SystemCallError.new(fun, val) if val != 0 rescue Errno::ERANGE size += 1024 raise if size > BUF_MAX buf = FFI::MemoryPointer.new(:char, size) retry end ptr = pbuf.read_pointer if ptr.null? raise Error, "no group found for '#{gid}'" end grp = GroupStruct.new(ptr) get_group_from_struct(grp) end
Returns the login for the current process.
# File lib/bsd/sys/admin.rb, line 76 def self.get_login buf = FFI::MemoryPointer.new(:char, 256) if getlogin_r(buf, buf.size) != 0 raise Error, "getlogin_r function failed: " + strerror(FFI.errno) end buf.read_string end
Returns a User
object for the given name or uid. Raises an error if a user cannot be found.
Examples:
Sys::Admin.get_user('joe') Sys::Admin.get_user(501)
# File lib/bsd/sys/admin.rb, line 94 def self.get_user(uid) buf = FFI::MemoryPointer.new(:char, 1024) pbuf = FFI::MemoryPointer.new(PasswdStruct) temp = PasswdStruct.new if uid.is_a?(String) if getpwnam_r(uid, temp, buf, buf.size, pbuf) != 0 raise Error, "getpwnam_r function failed: " + strerror(FFI.errno) end else if getpwuid_r(uid, temp, buf, buf.size, pbuf) != 0 raise Error, "getpwuid_r function failed: " + strerror(FFI.errno) end end ptr = pbuf.read_pointer if ptr.null? raise Error, "no user found for #{uid}" end pwd = PasswdStruct.new(ptr) get_user_from_struct(pwd) end
Returns an array of Group
objects for each user on the system.
# File lib/bsd/sys/admin.rb, line 180 def self.groups groups = [] begin setgrent() until (ptr = getgrent()).null? grp = GroupStruct.new(ptr) groups << get_group_from_struct(grp) end ensure endgrent() end groups end
Removes user
from group
on the specified domain
, or the localhost if no domain is specified.
# File lib/windows/sys/admin.rb, line 291 def self.remove_group_member(user, group, domain=nil) domain ||= Socket.gethostname adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group") adsi.Remove("WinNT://#{domain}/#{user}") rescue WIN32OLERuntimeError => err raise Error, err end
Returns an array of User
objects for each user on the system.
# File lib/bsd/sys/admin.rb, line 161 def self.users users = [] begin setpwent() until (ptr = getpwent()).null? pwd = PasswdStruct.new(ptr) users << get_user_from_struct(pwd) end ensure endpwent() end users end
Private Class Methods
Takes a GroupStruct
and converts it to a Group
object.
# File lib/bsd/sys/admin.rb, line 198 def self.get_group_from_struct(grp) Group.new do |g| g.name = grp[:gr_name] g.passwd = grp[:gr_passwd] g.gid = grp[:gr_gid] g.members = grp[:gr_mem].read_array_of_string end end
An internal, private method for getting a list of groups for a particular user. The first member is a list of group names, the second member is the primary group ID.
# File lib/windows/sys/admin.rb, line 76 def self.get_groups(domain, user) array = [] adsi = WIN32OLE.connect("WinNT://#{domain}/#{user},user") adsi.groups.each{ |g| array << g.name } [array, adsi.PrimaryGroupId] end
Retrieves the user's home directory. For local accounts query the registry. For domain accounts use ADSI and use the HomeDirectory.
# File lib/windows/sys/admin.rb, line 32 def self.get_home_dir(user, local = false, domain = nil) if local sec = Win32::Security::SID.open(user) key = HKEY + sec.to_s dir = nil begin Win32::Registry::HKEY_LOCAL_MACHINE.open(key) do |reg| dir = reg['ProfileImagePath'] end rescue Win32::Registry::Error # Not every local user has a home directory end else domain ||= Socket.gethostname adsi = WIN32OLE.connect("WinNT://#{domain}/#{user},user") dir = adsi.get('HomeDirectory') end dir end
Get lastlog information for the given user.
# File lib/bsd/sys/admin.rb, line 238 def self.get_lastlog_info(uid) logfile = '/var/log/lastlog' lastlog = LastlogStruct.new begin fd = open_c(logfile, File::RDONLY) if fd != -1 bytes = pread_c(fd, lastlog, lastlog.size, uid * lastlog.size) if bytes < 0 raise Error, "pread function failed: " + strerror(FFI.errno) end else nil # Ignore, improper permissions end ensure close_c(fd) if fd && fd >= 0 end lastlog end
An internal, private method for getting a list of members for any particular group.
# File lib/windows/sys/admin.rb, line 88 def self.get_members(domain, group) array = [] adsi = WIN32OLE.connect("WinNT://#{domain}/#{group}") adsi.members.each{ |g| array << g.name } array end
Takes a UserStruct and converts it to a User
object.
# File lib/bsd/sys/admin.rb, line 210 def self.get_user_from_struct(pwd) user = User.new do |u| u.name = pwd[:pw_name] u.passwd = pwd[:pw_passwd] u.uid = pwd[:pw_uid] u.gid = pwd[:pw_gid] u.change = Time.at(pwd[:pw_change]) u.access_class = pwd[:pw_class] u.gecos = pwd[:pw_gecos] u.dir = pwd[:pw_dir] u.shell = pwd[:pw_shell] u.expire = Time.at(pwd[:pw_expire]) end log = get_lastlog_info(user.uid) if log user.login_time = Time.at(log[:ll_time]) user.login_device = log[:ll_line].to_s user.login_host = log[:ll_host].to_s end user end
A private method that lower cases all keys, and converts them all to symbols.
# File lib/windows/sys/admin.rb, line 59 def self.munge_options(opts) rhash = {} opts.each{ |k, v| k = k.to_s.downcase.to_sym rhash[k] = v } rhash end