simple-unix-users 0.0.1
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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +1 -0
- data/lib/simple-unix-users.rb +22 -0
- data/lib/simple-unix-users/user.rb +40 -0
- data/lib/simple-unix-users/users.rb +78 -0
- data/lib/simple-unix-users/version.rb +3 -0
- data/simple-unix-users.gemspec +23 -0
- data/spec/simple-unix-users/passwd-sample +38 -0
- data/spec/simple-unix-users/user_spec.rb +41 -0
- data/spec/simple-unix-users/users_spec.rb +79 -0
- metadata +62 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Keith R. Bennett
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# SimpleUnixUsers
|
2
|
+
|
3
|
+
Reads and parses user information from /etc/passwd or a specified
|
4
|
+
filespec, and provides simple operations on the collection of users,
|
5
|
+
and individual users.
|
6
|
+
|
7
|
+
This code was written as an example of something Ruby could be useful
|
8
|
+
for when administering a Unix system.
|
9
|
+
|
10
|
+
It's just a starting point, and lacks necessary error checking and
|
11
|
+
polish.
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'simple-unix-users'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install simple-unix-users
|
27
|
+
:w
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'simple-unix-users'
|
33
|
+
|
34
|
+
users = Users.new
|
35
|
+
# or
|
36
|
+
users = Users.new('my-test-passwd-file')
|
37
|
+
```
|
38
|
+
|
39
|
+
Then you can use the services provided by the Users and User classes.
|
40
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "simple-unix-users/version"
|
2
|
+
|
3
|
+
if /darwin/ === RUBY_PLATFORM
|
4
|
+
$stderr.puts "
|
5
|
+
|
6
|
+
A message from the simple-unix-users gem...
|
7
|
+
|
8
|
+
Although simple-unix-users will read a passwd file on Mac OS,
|
9
|
+
it is not guaranteed to work correctly. In addition, according to the Mac's
|
10
|
+
/etc/passwd file:
|
11
|
+
|
12
|
+
# Note that this file is consulted directly only when the system is running
|
13
|
+
# in single-user mode. At other times this information is provided by
|
14
|
+
# Open Directory.
|
15
|
+
|
16
|
+
"
|
17
|
+
end
|
18
|
+
|
19
|
+
module SimpleUnixUsers
|
20
|
+
require_relative 'simple-unix-users/user'
|
21
|
+
require_relative 'simple-unix-users/users'
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# This class is for illustrative purposes and lacks necessary error handling.
|
2
|
+
|
3
|
+
# Stores state, and provides some useful behavior, relating to a given user.
|
4
|
+
class User
|
5
|
+
|
6
|
+
attr_accessor :name, :dummy_pw, :uid, :gid, :personal_data, :home_dir, :shell
|
7
|
+
|
8
|
+
NULL_SHELL = '/bin/false'
|
9
|
+
NULL_HOME_DIR = '/nonexistent'
|
10
|
+
|
11
|
+
def initialize(line)
|
12
|
+
@name, @dummy_pw, @uid, @gid, p_data, @home_dir, @shell = line.chomp.split(':')
|
13
|
+
@personal_data = p_data.split(',')
|
14
|
+
end
|
15
|
+
|
16
|
+
def uid_number
|
17
|
+
uid.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
def gid_number
|
21
|
+
gid.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def home_dir_size_in_mb
|
25
|
+
`du -sm #{home_dir}`.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_shell?
|
29
|
+
shell != NULL_SHELL
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_home_dir?
|
33
|
+
home_dir != NULL_HOME_DIR
|
34
|
+
end
|
35
|
+
|
36
|
+
def groups
|
37
|
+
`groups #{name}`.chomp.split(':').last.strip.split(' ')
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative 'user'
|
2
|
+
|
3
|
+
# This class is for illustrative purposes and lacks necessary error handling.
|
4
|
+
|
5
|
+
# Manages a collection of users (instances of class 'User'),
|
6
|
+
# optionally loaded from /etc/passwd.
|
7
|
+
class Users < Array
|
8
|
+
|
9
|
+
# Reads the user information from the passwd file, and returns
|
10
|
+
# a Users instance.
|
11
|
+
def self.from_passwd_file(filespec = '/etc/passwd')
|
12
|
+
file_lines = File.readlines(filespec)
|
13
|
+
non_comment_lines = file_lines.reject { |line| /^#/ === line }
|
14
|
+
Users.new(non_comment_lines)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Constructor; takes an array of passwd-formatted lines, or
|
18
|
+
# User instances, or any combination thereof.
|
19
|
+
def initialize(array)
|
20
|
+
array.each do |element|
|
21
|
+
user = element.is_a?(String) ? User.new(element) : element
|
22
|
+
self << user
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Methods that will return arrays of field objects (e.g. names).
|
27
|
+
def names; self.map(&:name) end
|
28
|
+
def uids; self.map(&:uid) end
|
29
|
+
def gids; self.map(&:gid) end
|
30
|
+
def personal_datas; self.map(&:personal_data) end
|
31
|
+
def home_dirs; self.map(&:home_dir) end
|
32
|
+
def shells; self.map(&:shell) end
|
33
|
+
|
34
|
+
def uid_numbers; self.map(&:uid_number) end
|
35
|
+
def gid_numbers; self.map(&:gid_number) end
|
36
|
+
|
37
|
+
# Returns a new instance of Users containing only those users
|
38
|
+
# whose shell is not '/bin/false'.
|
39
|
+
def having_shell
|
40
|
+
Users.new(select { |user| user.has_shell? })
|
41
|
+
end
|
42
|
+
|
43
|
+
def having_shell_of(shell)
|
44
|
+
Users.new(select { |user| user.shell == shell })
|
45
|
+
end
|
46
|
+
|
47
|
+
def not_having_shell
|
48
|
+
Users.new(self - having_shell)
|
49
|
+
end
|
50
|
+
|
51
|
+
def having_home_dir
|
52
|
+
Users.new(select { |user| user.has_home_dir? })
|
53
|
+
end
|
54
|
+
|
55
|
+
def not_having_home_dir
|
56
|
+
Users.new(select { |user| ! user.has_home_dir? })
|
57
|
+
# or, less efficiently: Users.new(self - having_home_dir)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns a new Users instance consisting only of
|
61
|
+
# those users having the specified group id.
|
62
|
+
def having_gid(gid)
|
63
|
+
gid = (gid.is_a?(Fixnum) ? gid.to_s : gid)
|
64
|
+
filtered_array = (select { |user| user.gid == gid })
|
65
|
+
Users.new(filtered_array)
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_by_name(name)
|
69
|
+
detect { |user| user.name == name }
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_by_uid(uid)
|
73
|
+
uid = uid.is_a?(String) ? uid : uid.to_s
|
74
|
+
detect { |user| user.uid == uid }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'simple-unix-users/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "simple-unix-users"
|
8
|
+
gem.version = SimpleUnixUsers::VERSION
|
9
|
+
gem.authors = ["Keith R. Bennett"]
|
10
|
+
gem.email = ["keithrbennett@gmail.com"]
|
11
|
+
gem.description = %q{
|
12
|
+
Reads and parses user information from /etc/passwd or a specified
|
13
|
+
filespec, and provides simple operations on the collection of users,
|
14
|
+
and individual users.
|
15
|
+
}
|
16
|
+
gem.summary = %q{Manages Unix user information based on the content of /etc/passwd.}
|
17
|
+
gem.homepage = "https://github.com/keithrbennett/simple-unix-users"
|
18
|
+
|
19
|
+
gem.files = `git ls-files`.split($/)
|
20
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
21
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
22
|
+
gem.require_paths = ["lib"]
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
root:x:0:0:root:/root:/bin/bash
|
2
|
+
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
|
3
|
+
bin:x:2:2:bin:/bin:/bin/sh
|
4
|
+
sys:x:3:3:sys:/dev:/bin/sh
|
5
|
+
sync:x:4:65534:sync:/bin:/bin/sync
|
6
|
+
games:x:5:60:games:/usr/games:/bin/sh
|
7
|
+
man:x:6:12:man:/var/cache/man:/bin/sh
|
8
|
+
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
|
9
|
+
mail:x:8:8:mail:/var/mail:/bin/sh
|
10
|
+
news:x:9:9:news:/var/spool/news:/bin/sh
|
11
|
+
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
|
12
|
+
proxy:x:13:13:proxy:/bin:/bin/sh
|
13
|
+
www-data:x:33:33:www-data:/var/www:/bin/sh
|
14
|
+
backup:x:34:34:backup:/var/backups:/bin/sh
|
15
|
+
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
|
16
|
+
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
|
17
|
+
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
|
18
|
+
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
|
19
|
+
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
|
20
|
+
syslog:x:101:103::/home/syslog:/bin/false
|
21
|
+
messagebus:x:102:105::/var/run/dbus:/bin/false
|
22
|
+
colord:x:103:108:colord colour management daemon,,,:/var/lib/colord:/bin/false
|
23
|
+
whoopsie:x:105:114::/nonexistent:/bin/false
|
24
|
+
avahi-autoipd:x:106:117:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
|
25
|
+
avahi:x:107:118:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
|
26
|
+
usbmux:x:108:46:usbmux daemon,,,:/home/usbmux:/bin/false
|
27
|
+
kernoops:x:109:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false
|
28
|
+
pulse:x:110:119:PulseAudio daemon,,,:/var/run/pulse:/bin/false
|
29
|
+
rtkit:x:111:122:RealtimeKit,,,:/proc:/bin/false
|
30
|
+
speech-dispatcher:x:112:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
|
31
|
+
hplip:x:113:7:HPLIP system user,,,:/var/run/hplip:/bin/false
|
32
|
+
saned:x:114:123::/home/saned:/bin/false
|
33
|
+
haldaemon:x:115:125:Hardware abstraction layer,,,:/var/run/hald:/bin/false
|
34
|
+
mdm:x:116:128:MDM Display Manager:/var/lib/mdm:/bin/false
|
35
|
+
kbennett:x:1000:1000:Keith Bennett,,,:/home/kbennett:/usr/bin/zsh
|
36
|
+
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
|
37
|
+
mysql:x:117:129:MySQL Server,,,:/nonexistent:/bin/false
|
38
|
+
postgres:x:118:130:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
require_relative '../../lib/simple-unix-users/user'
|
4
|
+
|
5
|
+
describe User do
|
6
|
+
|
7
|
+
subject { User.new( 'kbennett:x:1000:1000:Keith Bennett,,,:/home/kbennett:/usr/bin/zsh') }
|
8
|
+
|
9
|
+
it 'should create correctly from the passwd line' do
|
10
|
+
subject.class.should == User
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should create fields correctly' do
|
14
|
+
subject.name.should == 'kbennett'
|
15
|
+
subject.uid.should == '1000'
|
16
|
+
subject.gid.should == '1000'
|
17
|
+
subject.personal_data.first.should == 'Keith Bennett'
|
18
|
+
subject.home_dir.should == '/home/kbennett'
|
19
|
+
subject.shell.should == '/usr/bin/zsh'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should detect an existing home correctly' do
|
23
|
+
subject.has_home_dir?.should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should detect a nonexistent home correctly' do
|
27
|
+
subject.home_dir = User::NULL_HOME_DIR
|
28
|
+
subject.has_home_dir?.should be_false
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should calculate uid_number correctly' do
|
32
|
+
subject.uid_number.should == subject.uid.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should calculate gid_number correctly' do
|
36
|
+
subject.gid_number.should == subject.gid.to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
require_relative '../../lib/simple-unix-users/users.rb'
|
4
|
+
|
5
|
+
describe Users do
|
6
|
+
|
7
|
+
subject { Users.from_passwd_file(File.join(File.dirname(__FILE__), 'passwd-sample')) }
|
8
|
+
|
9
|
+
it 'should load a list of users' do
|
10
|
+
subject.should be_a Array
|
11
|
+
subject.should_not be_empty
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should return a list of names for the names function' do
|
15
|
+
names = subject.names.sort
|
16
|
+
names.sort.uniq.size.should > 1
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should be able to get uids as numbers' do
|
20
|
+
uid_numbers = subject.uid_numbers
|
21
|
+
uid_numbers.should_not be_empty
|
22
|
+
uid_numbers.first.should be_a(Fixnum)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should be able to get gids as numbers' do
|
26
|
+
gid_numbers = subject.gid_numbers
|
27
|
+
gid_numbers.should_not be_empty
|
28
|
+
gid_numbers.first.should be_a(Fixnum)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should be able to get the field objects arrays' do
|
32
|
+
[:names, :uids, :gids, :personal_datas, :home_dirs, :shells].each do |field|
|
33
|
+
array = subject.send(field)
|
34
|
+
array.size.should == subject.size
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should calculate having_shell correctly' do
|
39
|
+
num_with_shell = subject.inject(0) do |num, user|
|
40
|
+
num += 1 if user.has_shell?
|
41
|
+
num
|
42
|
+
end
|
43
|
+
subject.having_shell.size.should == num_with_shell
|
44
|
+
subject.not_having_shell.size.should == (subject.size - num_with_shell)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should correctly include users in having_shell_of' do
|
48
|
+
first_user = subject.first
|
49
|
+
subject.having_shell_of(first_user.shell).should include(first_user)
|
50
|
+
subject.having_shell_of('ja;ksdfja;sdfkajsdf;k').should_not include(first_user)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should correctly include users in having_home and not_having_home' do
|
54
|
+
user_with_home_dir = subject.detect { |user| user.has_home_dir? }
|
55
|
+
subject.having_home_dir.should include(user_with_home_dir)
|
56
|
+
subject.not_having_home_dir.should_not include(user_with_home_dir)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should correctly find users with having_gid' do
|
60
|
+
first_gid = subject.first.gid
|
61
|
+
having_first_gid = subject.having_gid(first_gid)
|
62
|
+
having_first_gid.should include(subject.first)
|
63
|
+
|
64
|
+
first_user_with_different_gid = subject.detect { |user| user.gid != first_gid }
|
65
|
+
having_first_gid.should_not include(first_user_with_different_gid)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should find_by_name correctly' do
|
69
|
+
last_user = subject.last
|
70
|
+
subject.find_by_name(last_user.name).should == last_user
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should find_by_uid correctly' do
|
74
|
+
last_user = subject.last
|
75
|
+
subject.find_by_uid(last_user.uid).should == last_user
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple-unix-users
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Keith R. Bennett
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-15 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! "\nReads and parses user information from /etc/passwd or a specified\nfilespec,
|
15
|
+
and provides simple operations on the collection of users,\nand individual users.\n "
|
16
|
+
email:
|
17
|
+
- keithrbennett@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- LICENSE.txt
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- lib/simple-unix-users.rb
|
28
|
+
- lib/simple-unix-users/user.rb
|
29
|
+
- lib/simple-unix-users/users.rb
|
30
|
+
- lib/simple-unix-users/version.rb
|
31
|
+
- simple-unix-users.gemspec
|
32
|
+
- spec/simple-unix-users/passwd-sample
|
33
|
+
- spec/simple-unix-users/user_spec.rb
|
34
|
+
- spec/simple-unix-users/users_spec.rb
|
35
|
+
homepage: https://github.com/keithrbennett/simple-unix-users
|
36
|
+
licenses: []
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.8.24
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Manages Unix user information based on the content of /etc/passwd.
|
59
|
+
test_files:
|
60
|
+
- spec/simple-unix-users/passwd-sample
|
61
|
+
- spec/simple-unix-users/user_spec.rb
|
62
|
+
- spec/simple-unix-users/users_spec.rb
|