1#!/usr/local/bin/perl -t
2
3# OpenVPN PAM AUTHENTICATON
4#   This script can be used to add PAM-based authentication
5#   to OpenVPN 2.0.  The OpenVPN client must provide
6#   a username/password, using the --auth-user-pass directive.
7#   The OpenVPN server should specify --auth-user-pass-verify
8#   with this script as the argument and the 'via-file' method
9#   specified.  The server can also optionally specify
10#   --client-cert-not-required and/or --username-as-common-name.
11
12# SCRIPT OPERATION
13#   Return success or failure status based on whether or not a
14#   given username/password authenticates using PAM.
15#   Caller should write username/password as two lines in a file
16#   which is passed to this script as a command line argument.
17
18# CAVEATS
19#   * Requires Authen::PAM module, which may also
20#     require the pam-devel package.
21#   * May need to be run as root in order to
22#     access username/password file.
23
24# NOTES
25#   * This script is provided mostly as a demonstration of the
26#     --auth-user-pass-verify script capability in OpenVPN.
27#     For real world usage, see the auth-pam module in the plugin
28#     folder.
29
30use Authen::PAM;
31use POSIX;
32
33# This "conversation function" will pass
34# $password to PAM when it asks for it.
35
36sub my_conv_func {
37    my @res;
38    while ( @_ ) {
39        my $code = shift;
40        my $msg = shift;
41        my $ans = "";
42
43        $ans = $password if $msg =~ /[Pp]assword/;
44
45        push @res, (PAM_SUCCESS(),$ans);
46    }
47    push @res, PAM_SUCCESS();
48    return @res;
49}
50
51# Identify service type to PAM
52$service = "login";
53
54# Get username/password from file
55
56if ($ARG = shift @ARGV) {
57    if (!open (UPFILE, "<$ARG")) {
58	print "Could not open username/password file: $ARG\n";
59	exit 1;
60    }
61} else {
62    print "No username/password file specified on command line\n";
63    exit 1;
64}
65
66$username = <UPFILE>;
67$password = <UPFILE>;
68
69if (!$username || !$password) {
70    print "Username/password not found in file: $ARG\n";
71    exit 1;
72}
73
74chomp $username;
75chomp $password;
76
77close (UPFILE);
78
79# Initialize PAM object
80
81if (!ref($pamh = new Authen::PAM($service, $username, \&my_conv_func))) {
82    print "Authen::PAM init failed\n";
83    exit 1;
84}
85
86# Authenticate with PAM
87
88$res = $pamh->pam_authenticate;
89
90# Return success or failure
91
92if ($res == PAM_SUCCESS()) {
93    exit 0;
94} else {
95    print "Auth '$username' failed, PAM said: ", $pamh->pam_strerror($res), "\n";
96    exit 1;
97}
98