/
PAM.pm
128 lines (90 loc) · 2.79 KB
/
PAM.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package Net::OpenVPN::Auth::PAM;
@ISA = qw(Net::OpenVPN::Auth);
use strict;
use warnings;
use Log::Log4perl;
use POSIX qw(ttyname);
use Authen::PAM qw(:constants);
=head1 NAME PAM
Pluggable authentication modules (PAM) authentication module, which is able
to authenticate using native PAM library.
=head1 OBJECT CONSTRUCTOR
=head2 Inherited parameters
B<required> (boolean, 1) successfull authentication result is required for authentication chain to return successful authentication
B<sufficient> (boolean, 0) successful authentication result is sufficient for entire authentication chain
=over
=head2 Module specific parameters
B<pam_service> (string, "openvpn") - PAM service name (usualy name of file in /etc/pam.d directory)
=cut
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = $class->SUPER::new(@_);
##################################################
# PUBLIC VARS #
##################################################
##################################################
# PRIVATE VARS #
##################################################
$self->{_name} = "PAM";
$self->{_log} = Log::Log4perl->get_logger(__PACKAGE__);
bless($self, $class);
# initialize object
$self->clearParams();
$self->setParams(@_);
return $self;
}
sub clearParams {
my ($self) = @_;
$self->SUPER::clearParams();
$self->{pam_service} = "openvpn";
return 1;
}
sub authenticate {
my ($self, $struct) = @_;
return 0 unless ($self->validateParamsStruct($struct));
my $tty_name = ttyname(fileno(STDIN));
# initialize pam object
my $pam = Authen::PAM->new(
$self->{pam_service},
$struct->{username},
# this pam conversation functiony is
# completely stolen from
# http://search.cpan.org/~nikip/Authen-PAM-0.16/PAM/FAQ.pod
sub {
my @res;
while (@_) {
my $code = shift;
my $msg = shift;
my $ans = "";
$ans = $struct->{username} if ($code == PAM_PROMPT_ECHO_ON());
$ans = $struct->{password} if ($code == PAM_PROMPT_ECHO_OFF());
push (@res, (PAM_SUCCESS(), $ans));
}
push (@res, PAM_SUCCESS());
return @res;
}
);
unless (ref($pam)) {
$self->{error} = "PAM initialization failed with error code $pam.";
$self->{_log}->error($self->{error});
return 0;
}
$pam->pam_set_item(PAM_TTY(), $tty_name);
$self->{_log}->debug("Authenticating against PAM service '" . $self->{pam_service} . "' as user '" . $struct->{username} . "' with password '" . $struct->{password}. "'.");
my $r = $pam->pam_authenticate();
unless ($r == PAM_SUCCESS()) {
$self->{error} = "PAM authentication failed: " . $pam->pam_strerror($r);
return 0;
}
return 1;
}
=head1 AUTHOR
Brane F. Gracnar
=cut
=head1 SEE ALSO
L<Net::OpenVPN::Auth>
L<Net::OpenVPN::AuthChain>
L<Authen::PAM>
=cut
1;