File Coverage

blib/lib/WE/DB/User.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # $Id: User.pm,v 1.13 2005/02/16 22:45:50 eserte Exp $
5             # Author: Olaf Mätzner
6             #
7             # Copyright (C) 2001 Online Office Berlin. All rights reserved.
8             # Copyright (C) 2002,2003 Slaven Rezic.
9             # This is free software; you can redistribute it and/or modify it under the
10             # terms of the GNU General Public License, see the file COPYING.
11              
12             #
13             # Mail: slaven@rezic.de
14             # WWW: http://we-framework.sourceforge.net
15             #
16              
17             package WE::DB::User;
18              
19 20     20   2684 use strict;
  20         42  
  20         816  
20 20     20   106 use vars qw($VERSION $ERROR);
  20         39  
  20         3198  
21             $VERSION = sprintf("%d.%02d", q$Revision: 1.13 $ =~ /(\d+)\.(\d+)/);
22              
23 20     20   18476 use DB_File;
  0            
  0            
24             use Fcntl;
25              
26             my $pwfile;
27             my $userdatabase;
28              
29             use constant PW => 0;
30             use constant GROUPS => 1;
31             use constant FULLNAME => 2;
32             use constant USERDEF => 3;
33              
34             use constant ERROR_OK => 1;
35              
36             sub new {
37             my($class, $root, $file, %args) = @_;
38             my $self = {};
39             $pwfile = $file;
40             bless $self, $class;
41              
42             $args{-readonly} = 0 unless defined $args{-readonly};
43             $args{-writeonly} = 0 unless defined $args{-writeonly};
44              
45             my $flags;
46             if ($args{-readonly}) {
47             $flags = O_RDONLY;
48             } elsif ($args{-writeonly}) {
49             $flags = O_RDWR;
50             } else {
51             $flags = O_RDWR|O_CREAT;
52             }
53              
54             if (!defined $args{-connect} || $args{-connect} ne 'never') {
55             tie %{$self->{DB}}, "DB_File", "$file", $flags, 0644 or die("can't tie db (file $file): $!");
56             }
57             $self->{DBFile} = $file;
58             $self;
59             }
60             sub disconnect {
61             my $self = shift;
62             eval {
63             untie %{ $self->{DB} };
64             };warn $@ if $@;
65             }
66             sub identify {
67             my($self, $user, $password) = @_;
68             my $ret = 0;
69             if ( $self->user_exists($user) ) {
70             my @things = split(/:/, $self->{DB}{$user}, -1);
71             my $cryptpw = $things[PW];
72             my $crypt = _decrypt($password, $cryptpw);
73             if ($crypt eq $cryptpw) { $ret=1 };
74             }
75             return $ret;
76             }
77             sub get_fullname {
78             my($self, $user) = @_;
79             if ( $self->user_exists($user) ) {
80             my @things = split(/:/, $self->{DB}{$user}, -1);
81             my $fullname = $things[FULLNAME];
82             if ($fullname) { return $fullname } else { return "" }
83             } else {
84             return 0;
85             }
86             }
87             sub user_exists {
88             my($self, $user) = @_;
89             my $ret = 0;
90             if ( $self->{DB}{$user} ) {$ret=1};
91             return $ret;
92             }
93             sub add_user {
94             my($self, $user, $password, $fullname, @userdef) = @_;
95             if (!$fullname) {$fullname="new user"};
96             my $ret = 0;
97             if ( $self->user_exists($user) ) {
98             $ERROR = "User $user exists already";
99             return 0;
100             };
101             if ( $user=~/:/ ) {
102             $ERROR = "Invalid character in user name";
103             return 0;
104             };
105             $self->{DB}{$user} = join(":",_encrypt($password),"",$fullname,@userdef);
106             return ERROR_OK;
107             }
108             sub update_user {
109             my($self, $user, $password, $fullname,$groups,@userdef) = @_;
110             if ( $self->user_exists($user) ) {
111             my @things = split(/:/, $self->{DB}{$user}, -1);
112             my $pw;
113             if ($password eq "") {
114             $password = $things[PW];
115             } else {
116             $password = _encrypt($password);
117             }
118             if ($fullname eq "") {
119             $fullname = $things[FULLNAME];
120             }
121             if ($groups eq "") {
122             $groups = $things[GROUPS];
123             }
124             if (!@userdef) {
125             @userdef = @things[USERDEF..$#things];
126             }
127             $self->{DB}{$user} = join(":",$password,$groups,$fullname,@userdef);
128             } else {
129             $ERROR = "User $user does not exist";
130             return 0;
131             };
132             }
133             sub delete_user {
134             my($self, $user) = @_;
135             my $ret = 0;
136             if ( !$self->{DB}{$user} ) {
137             return 0;
138             };
139             delete $self->{DB}{$user};
140             $ret=1;
141             return $ret;
142             }
143             sub is_in_group {
144             my($self, $user, $group) = @_;
145             my $ret=0;
146             if ( $self->user_exists($user) ) {
147             my @things = split(/:/, $self->{DB}{$user}, -1);
148             if ($things[GROUPS]) {
149             if ($things[GROUPS]=~/\b$group\b/) { $ret=1 };
150             }
151             }
152             return $ret;
153             }
154             sub get_groups {
155             my($self, $user) = @_;
156             my @groups;
157             if ($self->user_exists($user)) {
158             my @things = split(/:/, $self->{DB}{$user}, -1);
159             @groups = split(/\#/, $things[GROUPS] );
160             }
161             return @groups;
162             }
163             sub get_user {
164             my($self, $user) = @_;
165             if ($self->user_exists($user)) {
166             my @things = split(/:/, $self->{DB}{$user}, -1);
167             my @groups = split(/\#/, $things[GROUPS] );
168             return {
169             'groups' => \@groups,
170             'username' => $user,
171             'password' => $things[PW],
172             'fullname' => $things[FULLNAME],
173             'userdef' => [@things[USERDEF..$#things]],
174             };
175             } else {return 0}
176             }
177             sub add_group {
178             my($self, $user, $group) = @_;
179             my $ret=0;
180             if ($group=~/\#/) {
181             $ERROR = "Group name cannot contain # ";
182             return 0;
183             }
184             if ($self->is_in_group($user,$group)) {
185             return ERROR_OK; # $user already in $group
186             }
187             if ($self->user_exists($user)) {
188             my @things = split(/:/, $self->{DB}{$user}, -1);
189             my @groups;
190             if ($things[GROUPS] ) { @groups = split(/\#/, $things[GROUPS] ); }
191             push(@groups,$group);
192             $self->{DB}{$user} = join(":", $things[PW], join("#",@groups), @things[FULLNAME, USERDEF..$#things]);
193             $ret = ERROR_OK;
194             }
195             return $ret;
196             }
197             sub delete_group {
198             my($self, $user, $delgroup) = @_;
199             my $ret=0;
200             if ( $self->user_exists($user) && $self->is_in_group($user,$delgroup)) {
201             my @things = split(/:/, $self->{DB}{$user}, -1);
202             my @groups = $self->get_groups($user);
203             my @newgroups;
204             foreach my $g (@groups) {
205             if ($g ne $delgroup) { push(@newgroups,$g) }
206             }
207             $self->{DB}{$user} = join(":", $things[PW], join("#",@newgroups), @things[FULLNAME, USERDEF..$#things]);
208             $ret=1;
209             }
210             return $ret;
211             }
212             sub get_users_of_group {
213             my($self, $group) = @_;
214             my @users;
215             foreach my $usr (keys %{$self->{DB}}) {
216             if ( $self->is_in_group($usr,$group) ) { push(@users,$usr); }
217             }
218             return @users;
219             }
220             sub get_all_users {
221             my($self) = @_;
222             my @allusers;
223             foreach my $usr (keys %{$self->{DB}}) {
224             push(@allusers, $usr);
225             }
226             return @allusers;
227             }
228             sub get_all_groups {
229             my($self) = @_;
230             my %groups;
231             foreach my $usr (keys %{$self->{DB}}) {
232             foreach my $grp ( $self->get_groups($usr) ) {
233             $groups{$grp}=1;
234             }
235             }
236             $groups{'webusermanagers'}=1;
237             return keys %groups;
238             }
239             sub set_user_field {
240             my($self, $user, $field, $value) = @_;
241             if ($self->user_exists($user)) {
242             my @things = split(/:/, $self->{DB}{$user}, -1);
243             $things[USERDEF + $field] = $value;
244             $self->{DB}{$user} = join(":", @things);
245             1;
246             }
247             }
248             sub get_user_field {
249             my($self, $user, $field) = @_;
250             if ($self->user_exists($user)) {
251             my @things = split(/:/, $self->{DB}{$user}, -1);
252             return $things[USERDEF + $field];
253             }
254             }
255             sub _crypt {
256             my($password, $salt) = @_;
257             my $crypt;
258             eval {
259             local $SIG{__DIE__};
260             $crypt = crypt($password, $salt);
261             };
262             if ($@) { $crypt = $password };
263             $crypt;
264             }
265             sub _encrypt {
266             my $password = shift;
267             _crypt($password, &salt);
268             }
269             sub _decrypt {
270             my($checkit, $old_password) = @_;
271             _crypt($checkit, $old_password);
272             }
273             sub salt {
274             my($salt) = ''; # initialization
275             my($i, $rand) = (0, 0);
276             my(@itoa64) = ( '.', '/', 0 .. 9, 'a' .. 'z', 'A' .. 'Z' ); # 0 .. 63
277              
278             # to64
279             for ($i = 0; $i < 8; $i++) {
280             srand(time + $rand + $$);
281             $rand = rand(25*29*17 + $rand);
282             $salt .= $itoa64[$rand & $#itoa64];
283             }
284             #warn "Salt is: $salt\n";
285              
286             return $salt;
287             }
288             # Deprecated! XXX
289             sub error {
290             my($self, $errorcode) = @_;
291             my @errtxt;
292             $errtxt[0] = "not accepted";
293             $errtxt[1] = "ok";
294             $errtxt[2] = "invalid character";
295              
296             if ( $errtxt[$errorcode] ) {
297             return $errtxt[$errorcode];
298             } else {
299             return "unknown error.";
300             }
301             return 0;
302             }
303              
304             # Return 1 if this file is really a WE::DB::User file
305             sub check_data_format {
306             my $self = shift;
307             return 0 if exists $self->{DB}{__DBINFO__};
308             my($firstuser) = each %{ $self->{DB} };
309             if (!defined $firstuser) {
310             return 1; # it's empty
311             }
312             my @f = split /:/, $self->{DB}{$firstuser};
313             return @f >= 3; # at least password, groups, fullname
314             }
315              
316             # XXX del:
317             # sub delete_db {
318             # my $self = shift;
319             # unlink $self->{DBFile};
320             # }
321              
322             1;
323              
324             __END__