simple-unix-users 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simple-unix-users.gemspec
4
+ gemspec
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,3 @@
1
+ module SimpleUnixUsers
2
+ VERSION = "0.0.1"
3
+ end
@@ -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