sys-admin 1.5.6 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +8 -0
- data/MANIFEST +6 -3
- data/README +3 -17
- data/Rakefile +22 -51
- data/examples/example_groups.rb +27 -0
- data/examples/example_users.rb +41 -0
- data/lib/bsd/sys/admin.rb +239 -0
- data/lib/darwin/sys/admin.rb +227 -0
- data/lib/linux/sys/admin.rb +259 -0
- data/lib/sunos/sys/admin.rb +241 -0
- data/lib/sys/admin.rb +17 -0
- data/lib/sys/admin/common.rb +140 -0
- data/lib/sys/admin/custom.rb +16 -0
- data/lib/unix/sys/admin.rb +164 -0
- data/lib/windows/sys/admin.rb +971 -0
- data/sys-admin.gemspec +3 -2
- data/test/test_sys_admin.rb +3 -5
- data/test/test_sys_admin_unix.rb +96 -81
- data/test/test_sys_admin_windows.rb +16 -38
- metadata +67 -59
- data/examples/groups.rb +0 -39
- data/examples/users.rb +0 -53
- data/ext/extconf.rb +0 -72
- data/ext/sys/admin.c +0 -419
- data/ext/sys/admin.h +0 -515
| @@ -0,0 +1,227 @@ | |
| 1 | 
            +
            require 'sys/admin/custom'
         | 
| 2 | 
            +
            require 'sys/admin/common'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # The Darwin specific code.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Sys
         | 
| 7 | 
            +
              class Admin
         | 
| 8 | 
            +
                private
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                attach_function :getlogin_r, [:pointer, :int], :int
         | 
| 11 | 
            +
                attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 12 | 
            +
                attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 13 | 
            +
                attach_function :getgrnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 14 | 
            +
                attach_function :getgrgid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 15 | 
            +
                attach_function :getlastlogx, [:long, :pointer], :pointer
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getgrnam_r
         | 
| 18 | 
            +
                private_class_method :getgrgid_r, :getlastlogx
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                # struct passwd from /usr/include/pwd.h
         | 
| 21 | 
            +
                class PasswdStruct < FFI::Struct
         | 
| 22 | 
            +
                  layout(
         | 
| 23 | 
            +
                    :pw_name, :string,
         | 
| 24 | 
            +
                    :pw_passwd, :string,
         | 
| 25 | 
            +
                    :pw_uid, :uint,
         | 
| 26 | 
            +
                    :pw_gid, :uint,
         | 
| 27 | 
            +
                    :pw_change, :ulong,
         | 
| 28 | 
            +
                    :pw_class, :string,
         | 
| 29 | 
            +
                    :pw_gecos, :string,
         | 
| 30 | 
            +
                    :pw_dir, :string,
         | 
| 31 | 
            +
                    :pw_shell, :string,
         | 
| 32 | 
            +
                    :pw_expire, :ulong
         | 
| 33 | 
            +
                  )
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # struct group from /usr/include/grp.h
         | 
| 37 | 
            +
                class GroupStruct < FFI::Struct
         | 
| 38 | 
            +
                  layout(
         | 
| 39 | 
            +
                    :gr_name, :string,
         | 
| 40 | 
            +
                    :gr_passwd, :string,
         | 
| 41 | 
            +
                    :gr_gid, :uint,
         | 
| 42 | 
            +
                    :gr_mem, :pointer
         | 
| 43 | 
            +
                  )
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # I'm blending the timeval struct in directly here
         | 
| 47 | 
            +
                class LastlogxStruct < FFI::Struct
         | 
| 48 | 
            +
                  layout(
         | 
| 49 | 
            +
                    :tv_sec, :long,
         | 
| 50 | 
            +
                    :tv_usec, :long,
         | 
| 51 | 
            +
                    :ll_line, [:char, 32],
         | 
| 52 | 
            +
                    :ll_host, [:char, 256]
         | 
| 53 | 
            +
                  )
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                public
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                # Returns the login for the current process.
         | 
| 59 | 
            +
                #
         | 
| 60 | 
            +
                def self.get_login
         | 
| 61 | 
            +
                  buf = FFI::MemoryPointer.new(:char, 256)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  if getlogin_r(buf, buf.size) != 0
         | 
| 64 | 
            +
                    raise Error, "getlogin_r function failed: " + strerror(FFI.errno)
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  buf.read_string
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                # Returns a User object for the given name or uid. Raises an error
         | 
| 71 | 
            +
                # if a user cannot be found.
         | 
| 72 | 
            +
                #
         | 
| 73 | 
            +
                # Examples:
         | 
| 74 | 
            +
                #
         | 
| 75 | 
            +
                #    Sys::Admin.get_user('joe')
         | 
| 76 | 
            +
                #    Sys::Admin.get_user(501)
         | 
| 77 | 
            +
                #
         | 
| 78 | 
            +
                def self.get_user(uid)
         | 
| 79 | 
            +
                  buf  = FFI::MemoryPointer.new(:char, 1024)
         | 
| 80 | 
            +
                  pbuf = FFI::MemoryPointer.new(PasswdStruct)
         | 
| 81 | 
            +
                  temp = PasswdStruct.new
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  if uid.is_a?(String)
         | 
| 84 | 
            +
                    if getpwnam_r(uid, temp, buf, buf.size, pbuf) != 0
         | 
| 85 | 
            +
                      raise Error, "getpwnam_r function failed: " + strerror(FFI.errno)
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  else
         | 
| 88 | 
            +
                    if getpwuid_r(uid, temp, buf, buf.size, pbuf) != 0
         | 
| 89 | 
            +
                      raise Error, "getpwuid_r function failed: " + strerror(FFI.errno)
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  ptr = pbuf.read_pointer
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  if ptr.null?
         | 
| 96 | 
            +
                    raise Error, "no user found for #{uid}"
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  pwd = PasswdStruct.new(ptr)
         | 
| 100 | 
            +
                  get_user_from_struct(pwd)
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                # Returns a Group object for the given name or uid. Raises an error
         | 
| 104 | 
            +
                # if a group cannot be found.
         | 
| 105 | 
            +
                #
         | 
| 106 | 
            +
                # Examples:
         | 
| 107 | 
            +
                #
         | 
| 108 | 
            +
                #    Sys::Admin.get_group('admin')
         | 
| 109 | 
            +
                #    Sys::Admin.get_group(101)
         | 
| 110 | 
            +
                #
         | 
| 111 | 
            +
                def self.get_group(gid)
         | 
| 112 | 
            +
                  buf  = FFI::MemoryPointer.new(:char, 1024)
         | 
| 113 | 
            +
                  pbuf = FFI::MemoryPointer.new(PasswdStruct)
         | 
| 114 | 
            +
                  temp = GroupStruct.new
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  if gid.is_a?(String)
         | 
| 117 | 
            +
                    if getgrnam_r(gid, temp, buf, buf.size, pbuf) != 0
         | 
| 118 | 
            +
                      raise Error, "getgrnam_r function failed: " + strerror(FFI.errno)
         | 
| 119 | 
            +
                    end
         | 
| 120 | 
            +
                  else
         | 
| 121 | 
            +
                    if getgrgid_r(gid, temp, buf, buf.size, pbuf) != 0
         | 
| 122 | 
            +
                      raise Error, "getgrgid_r function failed: " + strerror(FFI.errno)
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  ptr = pbuf.read_pointer
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  if ptr.null?
         | 
| 129 | 
            +
                    raise Error, "no group found for #{gid}"
         | 
| 130 | 
            +
                  end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                  grp = GroupStruct.new(ptr)
         | 
| 133 | 
            +
                  get_group_from_struct(grp)
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                # Returns an array of User objects for each user on the system.
         | 
| 137 | 
            +
                #
         | 
| 138 | 
            +
                #--
         | 
| 139 | 
            +
                # This method is somewhat slow on OSX because of the call to get
         | 
| 140 | 
            +
                # lastlog information. I'm not sure why.
         | 
| 141 | 
            +
                #
         | 
| 142 | 
            +
                def self.users
         | 
| 143 | 
            +
                  users = []
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                  begin
         | 
| 146 | 
            +
                    setpwent()
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                    until (ptr = getpwent()).null?
         | 
| 149 | 
            +
                      pwd = PasswdStruct.new(ptr)
         | 
| 150 | 
            +
                      users << get_user_from_struct(pwd)
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  ensure
         | 
| 153 | 
            +
                    endpwent()
         | 
| 154 | 
            +
                  end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  users
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                # Returns an array of Group objects for each user on the system.
         | 
| 160 | 
            +
                #
         | 
| 161 | 
            +
                def self.groups
         | 
| 162 | 
            +
                  groups = []
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                  begin
         | 
| 165 | 
            +
                    setgrent()
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                    until (ptr = getgrent()).null?
         | 
| 168 | 
            +
                      grp = GroupStruct.new(ptr)
         | 
| 169 | 
            +
                      groups << get_group_from_struct(grp)
         | 
| 170 | 
            +
                    end
         | 
| 171 | 
            +
                  ensure
         | 
| 172 | 
            +
                    endgrent()
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  groups
         | 
| 176 | 
            +
                end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                private
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                # Takes a GroupStruct and converts it to a Group object.
         | 
| 181 | 
            +
                def self.get_group_from_struct(grp)
         | 
| 182 | 
            +
                  Group.new do |g|
         | 
| 183 | 
            +
                    g.name    = grp[:gr_name]
         | 
| 184 | 
            +
                    g.passwd  = grp[:gr_passwd]
         | 
| 185 | 
            +
                    g.gid     = grp[:gr_gid]
         | 
| 186 | 
            +
                    g.members = grp[:gr_mem].read_array_of_string
         | 
| 187 | 
            +
                  end
         | 
| 188 | 
            +
                end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                # Takes a UserStruct and converts it to a User object.
         | 
| 191 | 
            +
                def self.get_user_from_struct(pwd)
         | 
| 192 | 
            +
                  user = User.new do |u|
         | 
| 193 | 
            +
                    u.name         = pwd[:pw_name]
         | 
| 194 | 
            +
                    u.passwd       = pwd[:pw_passwd]
         | 
| 195 | 
            +
                    u.uid          = pwd[:pw_uid]
         | 
| 196 | 
            +
                    u.gid          = pwd[:pw_gid]
         | 
| 197 | 
            +
                    u.change       = Time.at(pwd[:pw_change])
         | 
| 198 | 
            +
                    u.access_class = pwd[:pw_class]
         | 
| 199 | 
            +
                    u.gecos        = pwd[:pw_gecos]
         | 
| 200 | 
            +
                    u.dir          = pwd[:pw_dir]
         | 
| 201 | 
            +
                    u.shell        = pwd[:pw_shell]
         | 
| 202 | 
            +
                    u.expire       = Time.at(pwd[:pw_expire])
         | 
| 203 | 
            +
                  end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                  log = get_lastlog_info(user.uid)
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                  if log
         | 
| 208 | 
            +
                    user.login_time = Time.at(log[:tv_sec])
         | 
| 209 | 
            +
                    user.login_device = log[:ll_line].to_s
         | 
| 210 | 
            +
                    user.login_host = log[:ll_host].to_s
         | 
| 211 | 
            +
                  end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                  user
         | 
| 214 | 
            +
                end
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                # Gets lastlog information for the given user.
         | 
| 217 | 
            +
                def self.get_lastlog_info(uid)
         | 
| 218 | 
            +
                  lastlog = LastlogxStruct.new
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                  # We don't check for failure here because most will fail due to
         | 
| 221 | 
            +
                  # lack of permissions and/or simple lack of information.
         | 
| 222 | 
            +
                  ptr = getlastlogx(uid, lastlog)
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                  ptr.null? ? nil : lastlog
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
              end
         | 
| 227 | 
            +
            end
         | 
| @@ -0,0 +1,259 @@ | |
| 1 | 
            +
            require 'sys/admin/custom'
         | 
| 2 | 
            +
            require 'sys/admin/common'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # The Linux specific code.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Sys
         | 
| 7 | 
            +
              class Admin
         | 
| 8 | 
            +
                private
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # I'm making some aliases here to prevent potential conflicts
         | 
| 11 | 
            +
                attach_function :open_c, :open, [:string, :int], :int
         | 
| 12 | 
            +
                attach_function :pread_c, :pread, [:int, :pointer, :size_t, :off_t], :size_t
         | 
| 13 | 
            +
                attach_function :close_c, :close, [:int], :int
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                attach_function :getlogin_r, [:pointer, :size_t], :int
         | 
| 16 | 
            +
                attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 17 | 
            +
                attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 18 | 
            +
                attach_function :getpwent_r, [:pointer, :pointer, :size_t, :pointer], :int
         | 
| 19 | 
            +
                attach_function :getgrent_r, [:pointer, :pointer, :size_t, :pointer], :int
         | 
| 20 | 
            +
                attach_function :getgrnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 21 | 
            +
                attach_function :getgrgid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getpwent_r
         | 
| 24 | 
            +
                private_class_method :getgrent_r, :getgrnam_r, :getgrgid_r
         | 
| 25 | 
            +
                private_class_method :open_c, :pread_c, :close_c
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                # struct passwd from /usr/include/pwd.h
         | 
| 28 | 
            +
                class PasswdStruct < FFI::Struct
         | 
| 29 | 
            +
                  layout(
         | 
| 30 | 
            +
                    :pw_name, :string,
         | 
| 31 | 
            +
                    :pw_passwd, :string,
         | 
| 32 | 
            +
                    :pw_uid, :uint,
         | 
| 33 | 
            +
                    :pw_gid, :uint,
         | 
| 34 | 
            +
                    :pw_gecos, :string,
         | 
| 35 | 
            +
                    :pw_dir, :string,
         | 
| 36 | 
            +
                    :pw_shell, :string
         | 
| 37 | 
            +
                  )
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                # struct group from /usr/include/grp.h
         | 
| 41 | 
            +
                class GroupStruct < FFI::Struct
         | 
| 42 | 
            +
                  layout(
         | 
| 43 | 
            +
                    :gr_name, :string,
         | 
| 44 | 
            +
                    :gr_passwd, :string,
         | 
| 45 | 
            +
                    :gr_gid, :uint,
         | 
| 46 | 
            +
                    :gr_mem, :pointer
         | 
| 47 | 
            +
                  )
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                # I'm blending the timeval struct in directly here
         | 
| 51 | 
            +
                class LastlogStruct < FFI::Struct
         | 
| 52 | 
            +
                  layout(
         | 
| 53 | 
            +
                    :ll_time, :uint,
         | 
| 54 | 
            +
                    :ll_line, [:char, 32],
         | 
| 55 | 
            +
                    :ll_host, [:char, 256]
         | 
| 56 | 
            +
                  )
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                public
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                # Returns the login for the current process.
         | 
| 62 | 
            +
                #
         | 
| 63 | 
            +
                def self.get_login
         | 
| 64 | 
            +
                  buf = FFI::MemoryPointer.new(:char, 256)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  if getlogin_r(buf, buf.size) != 0
         | 
| 67 | 
            +
                    raise Error, "getlogin_r function failed: " + strerror(FFI.errno)
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  buf.read_string
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                # Returns a User object for the given name or uid. Raises an error
         | 
| 74 | 
            +
                # if a user cannot be found.
         | 
| 75 | 
            +
                #
         | 
| 76 | 
            +
                # Examples:
         | 
| 77 | 
            +
                #
         | 
| 78 | 
            +
                #    Sys::Admin.get_user('joe')
         | 
| 79 | 
            +
                #    Sys::Admin.get_user(501)
         | 
| 80 | 
            +
                #
         | 
| 81 | 
            +
                def self.get_user(uid)
         | 
| 82 | 
            +
                  buf  = FFI::MemoryPointer.new(:char, 1024)
         | 
| 83 | 
            +
                  pbuf = FFI::MemoryPointer.new(PasswdStruct)
         | 
| 84 | 
            +
                  temp = PasswdStruct.new
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  if uid.is_a?(String)
         | 
| 87 | 
            +
                    if getpwnam_r(uid, temp, buf, buf.size, pbuf) != 0
         | 
| 88 | 
            +
                      raise Error, "getpwnam_r function failed: " + strerror(FFI.errno)
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
                  else
         | 
| 91 | 
            +
                    if getpwuid_r(uid, temp, buf, buf.size, pbuf) != 0
         | 
| 92 | 
            +
                      raise Error, "getpwuid_r function failed: " + strerror(FFI.errno)
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  ptr = pbuf.read_pointer
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  if ptr.null?
         | 
| 99 | 
            +
                    raise Error, "no user found for #{uid}"
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  pwd = PasswdStruct.new(ptr)
         | 
| 103 | 
            +
                  get_user_from_struct(pwd)
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                # Returns a Group object for the given name or uid. Raises an error
         | 
| 107 | 
            +
                # if a group cannot be found.
         | 
| 108 | 
            +
                #
         | 
| 109 | 
            +
                # Examples:
         | 
| 110 | 
            +
                #
         | 
| 111 | 
            +
                #    Sys::Admin.get_group('admin')
         | 
| 112 | 
            +
                #    Sys::Admin.get_group(101)
         | 
| 113 | 
            +
                #
         | 
| 114 | 
            +
                def self.get_group(gid)
         | 
| 115 | 
            +
                  buf  = FFI::MemoryPointer.new(:char, 1024)
         | 
| 116 | 
            +
                  pbuf = FFI::MemoryPointer.new(PasswdStruct)
         | 
| 117 | 
            +
                  temp = GroupStruct.new
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  if gid.is_a?(String)
         | 
| 120 | 
            +
                    if getgrnam_r(gid, temp, buf, buf.size, pbuf) != 0
         | 
| 121 | 
            +
                      raise Error, "getgrnam_r function failed: " + strerror(FFI.errno)
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                  else
         | 
| 124 | 
            +
                    if getgrgid_r(gid, temp, buf, buf.size, pbuf) != 0
         | 
| 125 | 
            +
                      raise Error, "getgrgid_r function failed: " + strerror(FFI.errno)
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  ptr = pbuf.read_pointer
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  if ptr.null?
         | 
| 132 | 
            +
                    raise Error, "no group found for #{gid}"
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  grp = GroupStruct.new(ptr)
         | 
| 136 | 
            +
                  get_group_from_struct(grp)
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                # Returns an array of User objects for each user on the system.
         | 
| 140 | 
            +
                #
         | 
| 141 | 
            +
                def self.users
         | 
| 142 | 
            +
                  users = []
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                  buf  = FFI::MemoryPointer.new(:char, 1024)
         | 
| 145 | 
            +
                  pbuf = FFI::MemoryPointer.new(PasswdStruct)
         | 
| 146 | 
            +
                  temp = PasswdStruct.new
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  begin
         | 
| 149 | 
            +
                    setpwent()
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                    while getpwent_r(temp, buf, buf.size, pbuf) == 0
         | 
| 152 | 
            +
                      ptr = pbuf.read_pointer
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                      break if ptr.null?
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                      pwd = PasswdStruct.new(ptr)
         | 
| 157 | 
            +
                      users << get_user_from_struct(pwd)
         | 
| 158 | 
            +
                    end
         | 
| 159 | 
            +
                  ensure
         | 
| 160 | 
            +
                    endpwent()
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  users
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                # Returns an array of Group objects for each user on the system.
         | 
| 167 | 
            +
                #
         | 
| 168 | 
            +
                def self.groups
         | 
| 169 | 
            +
                  groups = []
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  buf  = FFI::MemoryPointer.new(:char, 1024)
         | 
| 172 | 
            +
                  pbuf = FFI::MemoryPointer.new(GroupStruct)
         | 
| 173 | 
            +
                  temp = GroupStruct.new
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  begin
         | 
| 176 | 
            +
                    setgrent()
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                    while getgrent_r(temp, buf, buf.size, pbuf) == 0
         | 
| 179 | 
            +
                      ptr = pbuf.read_pointer
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                      break if ptr.null?
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                      grp = GroupStruct.new(ptr)
         | 
| 184 | 
            +
                      groups << get_group_from_struct(grp)
         | 
| 185 | 
            +
                    end
         | 
| 186 | 
            +
                  ensure
         | 
| 187 | 
            +
                    endgrent()
         | 
| 188 | 
            +
                  end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                  groups
         | 
| 191 | 
            +
                end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                private
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                # Takes a GroupStruct and converts it to a Group object.
         | 
| 196 | 
            +
                def self.get_group_from_struct(grp)
         | 
| 197 | 
            +
                  Group.new do |g|
         | 
| 198 | 
            +
                    g.name    = grp[:gr_name]
         | 
| 199 | 
            +
                    g.passwd  = grp[:gr_passwd]
         | 
| 200 | 
            +
                    g.gid     = grp[:gr_gid]
         | 
| 201 | 
            +
                    g.members = grp[:gr_mem].read_array_of_string
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                # Takes a UserStruct and converts it to a User object.
         | 
| 206 | 
            +
                def self.get_user_from_struct(pwd)
         | 
| 207 | 
            +
                  user = User.new do |u|
         | 
| 208 | 
            +
                    u.name         = pwd[:pw_name]
         | 
| 209 | 
            +
                    u.passwd       = pwd[:pw_passwd]
         | 
| 210 | 
            +
                    u.uid          = pwd[:pw_uid]
         | 
| 211 | 
            +
                    u.gid          = pwd[:pw_gid]
         | 
| 212 | 
            +
                    u.gecos        = pwd[:pw_gecos]
         | 
| 213 | 
            +
                    u.dir          = pwd[:pw_dir]
         | 
| 214 | 
            +
                    u.shell        = pwd[:pw_shell]
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  log = get_lastlog_info(user.uid)
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                  if log
         | 
| 220 | 
            +
                    login_device = log[:ll_line].to_s
         | 
| 221 | 
            +
                    login_host   = log[:ll_host].to_s
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                    user.login_time   = Time.at(log[:ll_time]) if log[:ll_time] > 0
         | 
| 224 | 
            +
                    user.login_device = login_device unless login_device.empty?
         | 
| 225 | 
            +
                    user.login_host   = login_host unless login_host.empty?
         | 
| 226 | 
            +
                  end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                  user
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                # Note: it seems that Linux, or at least Ubuntu, does not track logins
         | 
| 232 | 
            +
                # via GDM (Gnome Display Manager) for some reason, so this may not return
         | 
| 233 | 
            +
                # anything useful.
         | 
| 234 | 
            +
                #
         | 
| 235 | 
            +
                # The use of pread was necessary here because it's a sparse file.
         | 
| 236 | 
            +
                #
         | 
| 237 | 
            +
                def self.get_lastlog_info(uid)
         | 
| 238 | 
            +
                  logfile = '/var/log/lastlog'
         | 
| 239 | 
            +
                  lastlog = LastlogStruct.new
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                  begin
         | 
| 242 | 
            +
                    fd = open_c(logfile, File::RDONLY)
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                    if fd != -1
         | 
| 245 | 
            +
                      bytes = pread_c(fd, lastlog, lastlog.size, uid * lastlog.size)
         | 
| 246 | 
            +
                      if bytes < 0
         | 
| 247 | 
            +
                        raise Error, "pread function failed: " + strerror(FFI.errno)
         | 
| 248 | 
            +
                      end
         | 
| 249 | 
            +
                    else
         | 
| 250 | 
            +
                      nil # Ignore, improper permissions
         | 
| 251 | 
            +
                    end
         | 
| 252 | 
            +
                  ensure
         | 
| 253 | 
            +
                    close_c(fd) if fd && fd >= 0
         | 
| 254 | 
            +
                  end
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                  lastlog
         | 
| 257 | 
            +
                end
         | 
| 258 | 
            +
              end
         | 
| 259 | 
            +
            end
         |