├── .gitignore ├── HISTORY ├── LICENSE ├── MANIFEST ├── README ├── README.euc ├── extconf.rb ├── pwd ├── depend └── shadow.c ├── ruby-shadow.gemspec ├── shadow ├── depend └── shadow.c └── test └── basic_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | mkmf.log 3 | ruby-shadow-*.gem 4 | shadow.o 5 | shadow.so 6 | shadow.bundle 7 | -------------------------------------------------------------------------------- /HISTORY: -------------------------------------------------------------------------------- 1 | [2021/12/01] 2 | * Version 2.5.1 3 | - fixes for compiling for Ruby 3 4 | 5 | [2015/10/06] 6 | * Version 2.5.0 7 | - fixes for compiling for rubinius, at long last 8 | - TESTS 9 | - add a few method aliases 10 | 11 | [2014/12/02] 12 | * Version 2.4.1 13 | - sp_loginclass support should NOT have been added to password implementation 14 | [2014/12/01] 15 | * Version 2.4.0 16 | - Add support for sp_loginclass via pwd.h 17 | [2014/04/28] 18 | * Version 2.3.3 19 | - Added support for more BSDs, thanks to https://github.com/bsiegert. 20 | - Simplified compatibility check, removing check for function not actually used in pwd.h implementations. 21 | [2014/02/25] 22 | [2013/12/18] 23 | * Version 2.3.3 24 | Fix bug in shadow implementations (Linux, solaris) where sp_expired field was incorrectly set as nil. -1 is used to indicate not set. This was introduced 2.3.0. 25 | [2013/11/13] 26 | * Version 2.3.1 27 | - Caleb Land 28 | Remove sgetspent on implementations using pwd.h 29 | [2013/11/13] 30 | * Version 2.3.0 31 | - Caleb Land 32 | Merge OS X work into main gem. Fix bugs with OS X implementation and tweak support for FreeBSD. 33 | See https://github.com/caleb/ruby-shadow/commit/20d98b7d9e3bbbef0b737affd3245590096a316c 34 | - Add license file to Manifest. 35 | [2013/02/25] 36 | - Adam Palmblad 37 | Fix compilation issues with ruby 2. 38 | 39 | [2012/04/17] 40 | * Version 2.1.4 41 | - MATSUU Takuto 42 | Change obsolete C function to its proper replacement. 43 | * Version 2.1.3 44 | - MATSUU Takuto 45 | Fix a typo in the C code for rb_shadow_putspent. Typo has been present since 46 | ruby 1.9 code was added. 47 | [2011/02/08] 48 | * Version 2.1.2 49 | - Jeff Blaine <>, Adam Palmblad : 50 | Fix issues with compiling against Solaris. Apparently solaris does not offer sgetspent 51 | compiling against ruby 1.8; fixes were made to the ruby header path. 52 | [2011/02/08] 53 | * Version 2.1.1 54 | - Eric Hankins : Looks like there was a minor bug in 55 | compiling against ruby 1.8; fixes were made to the ruby header path. 56 | [2011/01/27] 57 | * Version 2.1 58 | - Ian Marlier : Make ruby-shadow compile under Ruby 1.9.2 59 | * STR2CSTR macro was removed in Ruby 1.9.2, after being deprecated in Ruby 1.8. Change 60 | to StringValuePtr() in its place. 61 | 62 | [2010/07/27] 63 | * Version 2.0 64 | - Adam Palmblad : Make ruby-shadow compile under Ruby 1.9 65 | 66 | [1999/08/18] 67 | * version 1.4.1 68 | - extconf.rb supports glibc2(libc6). 69 | 70 | [1999/03/09] 71 | * version 1.4 72 | - require ruby-1.3 or later version. 73 | - sShadowPasswd,mShadow,eFileLock was renamed. 74 | - FileLock class is inner class of Shadow Module. 75 | - lock,unlock was changed. 76 | - lock? method was added. 77 | - getspent,fgetspent doesn't raise EOFError 78 | - class hierarchy was changed. 79 | Shadow Module 80 | + Passwd Module 81 | + Entry Structure 82 | + Group Module (not implemented yet) 83 | + Entry Structure (not implemented yet) 84 | + FileLock Class 85 | 86 | [1998/12/17] 87 | * version 1.3 88 | - require ruby-1.1d0 or later version. 89 | 90 | [1998/10/31] 91 | * version 1.2 92 | - only some bug fix. 93 | 94 | [1998/08/31] 95 | * version 1.1 96 | - structure Shadow::ShadowPasswd is added. 97 | 98 | [1998/07/15] 99 | * version 1.0 released. 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | License: Free for any use with your own risk! 2 | 3 | OR 4 | 5 | The terms of the Public Domain License (http://creativecommons.org/licenses/publicdomain/) 6 | 7 | OR 8 | 9 | The terms of the Unlicense, https://spdx.org/licenses/Unlicense.html 10 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | extconf.rb 2 | HISTORY 3 | LICENSE 4 | MANIFEST 5 | README 6 | README.euc 7 | ruby-shadow.gemspec 8 | pwd/shadow.c 9 | pwd/depend 10 | shadow/shadow.c 11 | shadow/depend 12 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Shadow Password module 2 | 3 | Copyright (C) 1998-1999 Takaaki Tateishi 4 | Modified at: <1999/8/19 06:47:14 by ttate> 5 | License: See LICENSE 6 | 7 | 8 | 9 | 1. What's this 10 | 11 | This module provides tools to read, and, on Linux, append, information related to password files. 12 | 13 | Recent versions work on both Linux, Solaris, OS X, FreeBSD and OpenBSD. 14 | The functions found are translated to their equivalents in libshadow. 15 | 16 | Note 17 | 18 | 2. install 19 | 20 | ruby extconf.rb 21 | make # use gmake on FreeBSD 22 | (make install) 23 | 24 | * Note: 25 | Version 2 was developed to compile on Ruby 1.9. 1.8 compatibility should be 26 | still present, but no promises about earlier versions of Ruby. 27 | 28 | 3. Shadow::Passwd module's methods 29 | ________________________________________________________________________ 30 | Method | Linux | Solaris | OS X | *BSD 31 | ________________________________________________________________________ 32 | getspent | * | * | * | * 33 | getspnam(name) | * | * | * | * 34 | from_user_name(name) (alias of above) | * | * | * | * 35 | setspent | * | * | * | * 36 | endspent | * | * | * | * 37 | fgetspent(file) | * | * | N | N 38 | sgetspent(str) | * | N | N | N 39 | putspent(entry,file) | * | * | N | N 40 | add_password_entry (alias of above ) | * | * | N | N 41 | lckpwdf,lock | * | * | N | N 42 | ulckpwdf,unlock | * | * | N | N 43 | lock? | * | * | N | N 44 | 45 | Check the implementation in use via Shadow::IMPLEMENTATION. 46 | 47 | 4. Structure 48 | 49 | Shadow::Passwd::Entry (Struct::PasswdEntry) 50 | sp_namp - pointer to null-terminated user name. 51 | sp_pwdp - pointer to null-terminated password. 52 | sp_lstchg - days since Jan 1, 1970 password was last 53 | changed. 54 | sp_min - days before which password may not be changed. 55 | sp_max - days after which password must be changed. 56 | sp_warn - days before password is to expire that user is 57 | warned of pending password expiration. 58 | sp_inact - days after password expires that account is 59 | considered inactive and disabled. 60 | sp_expire - days since Jan 1, 1970 when account will be 61 | disabled 62 | sp_loginclass - pointer to null-terminated user login class. 63 | 64 | 65 | 5. Description 66 | 67 | getspent, getspname, fgetspent and sgetspent each return 68 | a structure Shadow::Passwd::Entry. getspent returns the 69 | next entry from the file, and fgetspent returns the next 70 | entry from the given stream. sgetspent returns a structure 71 | Shadow::Passwd::Entry using the provided string as input. 72 | getspnam searches from the current position in the file for 73 | an entry matching name. 74 | if you get EOF from each operation, you will get nil. 75 | 76 | setspent and endspent may be used to begin and end, respe- 77 | ctively, access to the shadow password file. 78 | 79 | lckpwdf(lock) and ulckpwdf(unlock) methods should be used 80 | to insure exclusive access to the /etc/shadow file. 81 | when either method fail, Exception Shadow::FileLock is raised. 82 | if you use lock as the iterator, unlock is automatically called 83 | when you exit the iterator block. 84 | 85 | 6. Reference 86 | 87 | * man shadow 88 | * /usr/include/shadow.h 89 | * Code at https://github.com/apalmblad/ruby-shadow 90 | 91 | 92 | Original Author: 93 | Takaaki Tateishi 94 | 95 | This GitHub repository is maintained by Adam Palmblad . I'll 96 | do my best to keep the repository reasonably up-to-date if you care to send pull requests. 97 | -------------------------------------------------------------------------------- /README.euc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apalmblad/ruby-shadow/f135b3fd52d0a638f2eb9b17a8952a7f0f317688/README.euc -------------------------------------------------------------------------------- /extconf.rb: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | # extconf.rb 3 | # 4 | # Modified at: <1999/8/19 06:38:55 by ttate> 5 | # 6 | 7 | require 'mkmf' 8 | require 'rbconfig' 9 | 10 | $CFLAGS = case RUBY_VERSION 11 | when /^1\.9/; '-DRUBY19' 12 | when /^2\./; '-DRUBY19' 13 | when /^3\./; '-DRUBY19' 14 | else; '' 15 | end 16 | 17 | implementation = case CONFIG['host_os'] 18 | when /linux/i; 'shadow' 19 | when /sunos|solaris/i; 'shadow' 20 | when /freebsd|mirbsd|netbsd|openbsd/i; 'pwd' 21 | when /darwin/i; 'pwd' 22 | else; nil 23 | "This library works on OS X, FreeBSD, MirBSD, NetBSD, OpenBSD, Solaris and Linux." 24 | end 25 | 26 | ok = true 27 | 28 | case implementation 29 | when 'shadow' 30 | #$LDFLAGS = "-lshadow" 31 | 32 | if( ! (ok &= have_library("shadow","getspent")) ) 33 | $LDFLAGS = "" 34 | ok = have_func("getspent") 35 | end 36 | 37 | ok &= have_func("fgetspent") 38 | ok &= have_func("setspent") 39 | ok &= have_func("endspent") 40 | ok &= have_func("lckpwdf") 41 | ok &= have_func("ulckpwdf") 42 | 43 | if ok 44 | if !have_func("sgetspent") 45 | $CFLAGS += ' -DSOLARIS' 46 | end 47 | end 48 | when 'pwd' 49 | ok &= have_func("endpwent") 50 | ok &= have_func("getpwent") 51 | ok &= have_func("getpwnam") 52 | ok &= have_func("getpwuid") 53 | ok &= have_func("setpassent") 54 | ok &= have_func("setpwent") 55 | 56 | have_header("uuid/uuid.h") 57 | have_header("uuid.h") 58 | else 59 | ok = false 60 | end 61 | 62 | have_header( "ruby/io.h") 63 | 64 | if ok 65 | 66 | create_makefile("shadow", implementation) 67 | else 68 | raise "You are missing some of the required functions from either shadow.h on Linux/Solaris, or pwd.h on FreeBSD/MirBSD/NetBSD/OpenBSD/OS X." 69 | end 70 | -------------------------------------------------------------------------------- /pwd/depend: -------------------------------------------------------------------------------- 1 | shadow.o: shadow.c 2 | -------------------------------------------------------------------------------- /pwd/shadow.c: -------------------------------------------------------------------------------- 1 | /* 2 | * shadow.c 3 | * 4 | * Ruby extention module for using FreeBSD/OpenBSD/OS X pwd.h. 5 | * 6 | * Copyright (C) 1998-1999 by Takaaki.Tateishi(ttate@jaist.ac.jp) 7 | * License: Free for any use with your own risk! 8 | */ 9 | #include 10 | #include 11 | #include 12 | #ifdef HAVE_UUID_UUID_H 13 | #include 14 | #elif HAVE_UUID_H 15 | #include 16 | #endif 17 | #define PWTYPE struct passwd 18 | 19 | #include "ruby.h" 20 | #ifdef HAVE_RUBY_IO_H 21 | #include "ruby/io.h" 22 | #else 23 | #include "rubyio.h" 24 | #endif 25 | 26 | #ifdef RUBY19 27 | #define file_ptr(x) (x)->stdio_file 28 | #else 29 | #define file_ptr(x) (x)->f 30 | #endif 31 | 32 | static VALUE rb_mShadow; 33 | static VALUE rb_mPasswd; 34 | static VALUE rb_sPasswdEntry; 35 | static VALUE rb_mGroup; 36 | static VALUE rb_sGroupEntry; 37 | static VALUE rb_eFileLock; 38 | 39 | 40 | static VALUE 41 | rb_shadow_setspent(VALUE self) 42 | { 43 | setpassent(1); 44 | return Qnil; 45 | } 46 | 47 | 48 | static VALUE 49 | rb_shadow_endspent(VALUE self) 50 | { 51 | endpwent(); 52 | return Qnil; 53 | } 54 | 55 | static VALUE convert_pw_struct( struct passwd *entry ) 56 | { 57 | /* Hmm. Why custom pw_change instead of sp_lstchg? */ 58 | return rb_struct_new(rb_sPasswdEntry, 59 | rb_tainted_str_new2(entry->pw_name), /* sp_namp */ 60 | rb_tainted_str_new2(entry->pw_passwd), /* sp_pwdp, encryped password */ 61 | Qnil, /* sp_lstchg, date when the password was last changed (in days since Jan 1, 1970) */ 62 | Qnil, /* sp_min, days that password must stay same */ 63 | Qnil, /* sp_max, days until password changes. */ 64 | Qnil, /* sp_warn, days before expiration where user is warned */ 65 | Qnil, /* sp_inact, days after password expiration that account becomes inactive */ 66 | INT2FIX(difftime(entry->pw_change, 0) / (24*60*60)), /* pw_change */ 67 | INT2FIX(difftime(entry->pw_expire, 0) / (24*60*60)), /* sp_expire */ 68 | Qnil, /* sp_flag */ 69 | rb_tainted_str_new2(entry->pw_class), /* sp_loginclass, user access class */ 70 | NULL); 71 | } 72 | 73 | static VALUE 74 | rb_shadow_getspent(VALUE self) 75 | { 76 | PWTYPE *entry; 77 | VALUE result; 78 | entry = getpwent(); 79 | 80 | if( entry == NULL ) 81 | return Qnil; 82 | 83 | result = convert_pw_struct( entry ); 84 | return result; 85 | } 86 | 87 | static VALUE 88 | rb_shadow_getspnam(VALUE self, VALUE name) 89 | { 90 | PWTYPE *entry; 91 | VALUE result; 92 | 93 | if( TYPE(name) != T_STRING ) 94 | rb_raise(rb_eException,"argument must be a string."); 95 | entry = getpwnam(StringValuePtr(name)); 96 | 97 | if( entry == NULL ) 98 | return Qnil; 99 | 100 | result = convert_pw_struct( entry ); 101 | return result; 102 | } 103 | 104 | void 105 | Init_shadow() 106 | { 107 | rb_sPasswdEntry = rb_struct_define("PasswdEntry", 108 | "sp_namp","sp_pwdp","sp_lstchg", 109 | "sp_min","sp_max","sp_warn", 110 | "sp_inact","pw_change", 111 | "sp_expire","sp_flag", 112 | "sp_loginclass", NULL); 113 | rb_sGroupEntry = rb_struct_define("GroupEntry", 114 | "sg_name","sg_passwd", 115 | "sg_adm","sg_mem",NULL); 116 | 117 | rb_mShadow = rb_define_module("Shadow"); 118 | rb_define_const( rb_mShadow, "IMPLEMENTATION", rb_str_new_cstr( "PWD" ) ); 119 | rb_eFileLock = rb_define_class_under(rb_mShadow,"FileLock",rb_eException); 120 | rb_mPasswd = rb_define_module_under(rb_mShadow,"Passwd"); 121 | rb_define_const(rb_mPasswd,"Entry",rb_sPasswdEntry); 122 | rb_mGroup = rb_define_module_under(rb_mShadow,"Group"); 123 | rb_define_const(rb_mGroup,"Entry",rb_sGroupEntry); 124 | 125 | rb_define_module_function(rb_mPasswd,"setspent",rb_shadow_setspent,0); 126 | rb_define_module_function(rb_mPasswd,"endspent",rb_shadow_endspent,0); 127 | rb_define_module_function(rb_mPasswd,"getspent",rb_shadow_getspent,0); 128 | rb_define_module_function(rb_mPasswd,"getspnam",rb_shadow_getspnam,1); 129 | rb_define_module_function(rb_mPasswd,"from_user_name",rb_shadow_getspnam,1); 130 | } 131 | -------------------------------------------------------------------------------- /ruby-shadow.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | Gem::Specification.new do |spec| 4 | spec.authors = ['Adam Palmblad', 5 | 'Eric Hankins', 6 | 'Ian Marlier', 7 | 'Jeff Blaine', 8 | 'Remi Broemeling', 9 | 'Takaaki Tateishi'] 10 | 11 | spec.description = 'This module provides access to shadow passwords on Linux, OSX, FreeBSD, OpenBSD, and Solaris' 12 | spec.email = ['adam.palmblad@teampages.com'] 13 | spec.extensions = ['extconf.rb'] 14 | spec.files = [] 15 | File.open('MANIFEST').each do |file| 16 | spec.files << file.chomp 17 | end 18 | spec.homepage = 'https://github.com/apalmblad/ruby-shadow' 19 | spec.name = 'ruby-shadow' 20 | spec.required_ruby_version = ['>= 1.8'] 21 | spec.summary = '*nix Shadow Password Module' 22 | spec.version = '2.5.1' 23 | spec.license = "Unlicense" 24 | end 25 | -------------------------------------------------------------------------------- /shadow/depend: -------------------------------------------------------------------------------- 1 | shadow.o: shadow.c 2 | -------------------------------------------------------------------------------- /shadow/shadow.c: -------------------------------------------------------------------------------- 1 | /* 2 | * shadow.c 3 | * 4 | * Ruby extention module for using Linux shadow password. 5 | * 6 | * Copyright (C) 1998-1999 by Takaaki.Tateishi(ttate@jaist.ac.jp) 7 | * License: Free for any use with your own risk! 8 | */ 9 | 10 | #include 11 | #include "ruby.h" 12 | #ifdef HAVE_RUBY_IO_H 13 | #include "ruby/io.h" 14 | #else 15 | #include "rubyio.h" 16 | #endif 17 | 18 | #ifdef RUBY19 19 | #define file_ptr(x) rb_io_stdio_file(x) 20 | #else 21 | #define file_ptr(x) (x)->f 22 | #endif 23 | 24 | #define NUM_FIELDS 10 25 | 26 | static VALUE rb_mShadow; 27 | static VALUE rb_mPasswd; 28 | static VALUE rb_sPasswdEntry; 29 | static VALUE rb_mGroup; 30 | static VALUE rb_sGroupEntry; 31 | static VALUE rb_eFileLock; 32 | 33 | 34 | static VALUE convert_pw_struct( struct spwd *entry ) 35 | { 36 | return rb_struct_new(rb_sPasswdEntry, 37 | rb_tainted_str_new2(entry->sp_namp), 38 | rb_tainted_str_new2(entry->sp_pwdp), 39 | INT2FIX(entry->sp_lstchg), 40 | INT2FIX(entry->sp_min), 41 | INT2FIX(entry->sp_max), 42 | INT2FIX(entry->sp_warn), 43 | INT2FIX(entry->sp_inact), 44 | Qnil, /* used by BSD, pw_change, date when the password expires, in days since Jan 1, 1970 */ 45 | INT2FIX(entry->sp_expire), 46 | INT2FIX(entry->sp_flag), 47 | Qnil, 48 | NULL); 49 | }; 50 | static VALUE 51 | rb_shadow_setspent(VALUE self) 52 | { 53 | setspent(); 54 | return Qnil; 55 | }; 56 | 57 | 58 | static VALUE 59 | rb_shadow_endspent(VALUE self) 60 | { 61 | endspent(); 62 | return Qnil; 63 | }; 64 | 65 | 66 | #ifndef SOLARIS 67 | static VALUE 68 | rb_shadow_sgetspent(VALUE self, VALUE str) 69 | { 70 | struct spwd *entry; 71 | VALUE result; 72 | 73 | if( TYPE(str) != T_STRING ) 74 | rb_raise(rb_eException,"argument must be a string."); 75 | 76 | entry = sgetspent(StringValuePtr(str)); 77 | 78 | if( entry == NULL ) 79 | return Qnil; 80 | 81 | result = convert_pw_struct( entry ); 82 | free(entry); 83 | return result; 84 | }; 85 | #endif 86 | 87 | static VALUE 88 | rb_shadow_fgetspent(VALUE self, VALUE file) 89 | { 90 | struct spwd *entry; 91 | VALUE result; 92 | 93 | if( TYPE(file) != T_FILE ) 94 | rb_raise(rb_eTypeError,"argument must be a File."); 95 | entry = fgetspent( file_ptr( (RFILE(file)->fptr) ) ); 96 | 97 | if( entry == NULL ) 98 | return Qnil; 99 | 100 | result = convert_pw_struct( entry ); 101 | return result; 102 | }; 103 | 104 | static VALUE 105 | rb_shadow_getspent(VALUE self) 106 | { 107 | struct spwd *entry; 108 | VALUE result; 109 | 110 | entry = getspent(); 111 | 112 | if( entry == NULL ) 113 | return Qnil; 114 | 115 | return convert_pw_struct( entry ); 116 | }; 117 | 118 | static VALUE 119 | rb_shadow_getspnam(VALUE self, VALUE name) 120 | { 121 | struct spwd *entry; 122 | VALUE result; 123 | 124 | if( TYPE(name) != T_STRING ) 125 | rb_raise(rb_eException,"argument must be a string."); 126 | 127 | entry = getspnam(StringValuePtr(name)); 128 | 129 | if( entry == NULL ) 130 | return Qnil; 131 | return convert_pw_struct( entry ); 132 | }; 133 | 134 | 135 | 136 | static VALUE 137 | rb_shadow_putspent(VALUE self, VALUE entry, VALUE file) 138 | { 139 | struct spwd centry; 140 | FILE* cfile; 141 | VALUE val[NUM_FIELDS]; 142 | int i; 143 | int result; 144 | 145 | if( TYPE(file) != T_FILE ) 146 | rb_raise(rb_eTypeError,"argument must be a File."); 147 | /* 148 | for(i=0; iptr[i]; 151 | i//val[i] = rb_struct_aref( entry, i ); 152 | } 153 | */ 154 | cfile = file_ptr( RFILE(file)->fptr ); 155 | 156 | VALUE x = rb_ary_entry( entry, 0 ); 157 | centry.sp_namp = StringValuePtr( x ); 158 | x = rb_ary_entry( entry, 1 ); 159 | centry.sp_pwdp = StringValuePtr( x ); 160 | centry.sp_lstchg = FIX2INT( rb_ary_entry( entry, 2) ); 161 | centry.sp_min = FIX2INT( rb_ary_entry( entry, 3 ) ); 162 | centry.sp_max = FIX2INT( rb_ary_entry( entry, 4 ) ); 163 | centry.sp_warn = FIX2INT( rb_ary_entry( entry, 5 )); 164 | centry.sp_inact = FIX2INT( rb_ary_entry( entry, 6 ) ); 165 | // missing 7 I think is put in to deal with beign similar to BSD returns, for the value pw_change. 166 | centry.sp_expire = FIX2INT( rb_ary_entry( entry, 8 ) ); 167 | centry.sp_flag = FIX2INT( rb_ary_entry( entry, 9 ) ); 168 | 169 | result = putspent(¢ry,cfile); 170 | 171 | if( result == -1 ) 172 | rb_raise(rb_eStandardError,"can't change password"); 173 | 174 | return Qtrue; 175 | }; 176 | 177 | 178 | static VALUE 179 | rb_shadow_lckpwdf(VALUE self) 180 | { 181 | int result; 182 | result = lckpwdf(); 183 | if( result == -1 ) 184 | rb_raise(rb_eFileLock,"password file was locked"); 185 | else 186 | return Qtrue; 187 | }; 188 | 189 | static int in_lock; 190 | 191 | static VALUE 192 | rb_shadow_lock(VALUE self) 193 | { 194 | int result; 195 | 196 | if( rb_block_given_p() ){ 197 | result = lckpwdf(); 198 | if( result == -1 ){ 199 | rb_raise(rb_eFileLock,"password file was locked"); 200 | } 201 | else{ 202 | in_lock++; 203 | rb_yield(Qnil); 204 | in_lock--; 205 | ulckpwdf(); 206 | }; 207 | return Qtrue; 208 | } 209 | else{ 210 | return rb_shadow_lckpwdf(self); 211 | }; 212 | }; 213 | 214 | 215 | static VALUE 216 | rb_shadow_ulckpwdf(VALUE self) 217 | { 218 | if( in_lock ){ 219 | rb_raise(rb_eFileLock,"you call unlock method in lock iterator."); 220 | }; 221 | ulckpwdf(); 222 | return Qtrue; 223 | }; 224 | 225 | static VALUE 226 | rb_shadow_unlock(VALUE self) 227 | { 228 | return rb_shadow_ulckpwdf(self); 229 | }; 230 | 231 | static VALUE 232 | rb_shadow_lock_p(VALUE self) 233 | { 234 | int result; 235 | 236 | result = lckpwdf(); 237 | if( result == -1 ){ 238 | return Qtrue; 239 | } 240 | else{ 241 | ulckpwdf(); 242 | return Qfalse; 243 | }; 244 | }; 245 | 246 | 247 | void 248 | Init_shadow() 249 | { 250 | rb_sPasswdEntry = rb_struct_define("PasswdEntry", 251 | "sp_namp","sp_pwdp","sp_lstchg", 252 | "sp_min","sp_max","sp_warn", 253 | "sp_inact", "pw_change", 254 | "sp_expire","sp_flag", 255 | "sp_loginclass", NULL); 256 | rb_sGroupEntry = rb_struct_define("GroupEntry", 257 | "sg_name","sg_passwd", 258 | "sg_adm","sg_mem",NULL); 259 | 260 | rb_mShadow = rb_define_module("Shadow"); 261 | rb_define_const( rb_mShadow, "IMPLEMENTATION", rb_str_new_cstr( "SHADOW" ) ); 262 | rb_eFileLock = rb_define_class_under(rb_mShadow,"FileLock",rb_eException); 263 | rb_mPasswd = rb_define_module_under(rb_mShadow,"Passwd"); 264 | rb_define_const(rb_mPasswd,"Entry",rb_sPasswdEntry); 265 | rb_mGroup = rb_define_module_under(rb_mShadow,"Group"); 266 | rb_define_const(rb_mGroup,"Entry",rb_sGroupEntry); 267 | 268 | rb_define_module_function(rb_mPasswd,"setspent",rb_shadow_setspent,0); 269 | rb_define_module_function(rb_mPasswd,"endspent",rb_shadow_endspent,0); 270 | #ifndef SOLARIS 271 | rb_define_module_function(rb_mPasswd,"sgetspent",rb_shadow_sgetspent,1); 272 | #endif 273 | rb_define_module_function(rb_mPasswd,"fgetspent",rb_shadow_fgetspent,1); 274 | rb_define_module_function(rb_mPasswd,"getspent",rb_shadow_getspent,0); 275 | rb_define_module_function(rb_mPasswd,"getspnam",rb_shadow_getspnam,1); 276 | rb_define_module_function(rb_mPasswd,"from_user_name",rb_shadow_getspnam,1); 277 | rb_define_module_function(rb_mPasswd,"putspent",rb_shadow_putspent,2); 278 | rb_define_module_function(rb_mPasswd,"add_password_entry",rb_shadow_putspent,2); 279 | rb_define_module_function(rb_mPasswd,"lckpwdf",rb_shadow_lckpwdf,0); 280 | rb_define_module_function(rb_mPasswd,"lock",rb_shadow_lock,0); 281 | rb_define_module_function(rb_mPasswd,"ulckpwdf",rb_shadow_ulckpwdf,0); 282 | rb_define_module_function(rb_mPasswd,"unlock",rb_shadow_unlock,0); 283 | rb_define_module_function(rb_mPasswd,"lock?",rb_shadow_lock_p,0); 284 | }; 285 | -------------------------------------------------------------------------------- /test/basic_test.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'rubygems' 3 | require 'shadow' 4 | require 'stringio' 5 | class RubyShadowTest < Test::Unit::TestCase 6 | STRUCT_METHODS = %w( sp_namp sp_pwdp sp_lstchg sp_min sp_max sp_warn sp_inact sp_expire sp_loginclass ) 7 | # --------------------------------------------------- test_smoke_test_getspent 8 | def test_smoke_test_getspent 9 | x = Shadow::Passwd.getspent 10 | assert( x, "ensure you have permissions to check this (sudo?)" ) 11 | check_struct( x ) 12 | end 13 | # ----------------------------------------------------- test_getspnam_for_user 14 | def test_getspnam_for_user 15 | user = `whoami`.strip 16 | x = Shadow::Passwd.getspnam( user ) 17 | assert( x, "ensure you have permissions to check this (sudo?)" ) 18 | check_struct( x ) 19 | end 20 | # ---------------------------------------- test_getspnam_for_non_existent_user 21 | def test_getspnam_for_non_existent_user 22 | assert_nil( Shadow::Passwd.getspnam( 'somebadusername' ) ) 23 | end 24 | # -------------------------------------------------------------- test_putspent 25 | def test_putspent 26 | omit_if( Shadow::IMPLEMENTATION != 'SHADOW' ) if respond_to?( :omit_if ) 27 | #result = StringIO.open( '', 'w' ) do |fh| 28 | File.open( 'test_password', 'w' ) do |fh| 29 | Shadow::Passwd.add_password_entry( sample_entry, fh ) 30 | end 31 | assert( File.read( 'test_password' ).match( sample_entry.first ) ) 32 | end 33 | # --------------------------------------------------------------- check_struct 34 | def check_struct( s ) 35 | STRUCT_METHODS.each do |m| 36 | s.send( m ) 37 | end 38 | end 39 | # ----------------------------------------------------------------- test_entry 40 | def sample_entry( &block ) 41 | return ['test_user', # sp_namp 42 | 'new_pass', # sp_pwdp 43 | 0, #sp_lastchg 44 | 0, #sp_min 45 | 0, #sp_max 46 | 0, #sp_warn 47 | 0, #sp_inact 48 | 0, #???? 49 | 0, #sp_expire 50 | 0 # sp_flag 51 | ] 52 | e = Shadow::Passwd::Entry.new 53 | e.sp_namp = 'test_user' 54 | e.sp_pwdp = 'password' 55 | yield e if block_given? 56 | return e 57 | end 58 | end 59 | 60 | --------------------------------------------------------------------------------