-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathauth_cvm_unix_local
143 lines (103 loc) · 3.84 KB
/
auth_cvm_unix_local
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!perl -w
=head1 NAME
auth_cvm_unix_local - SMTP AUTH LOGIN module using
Bruce Guenther's Credential Validation Module (CVM)
http://untroubled.org/cvm/
=head1 SYNOPSIS
In config/plugins:
auth/auth_cvm_unix_local \
cvm_socket /var/lib/cvm/cvm-unix-local.socket \
enable_smtp no \
enable_ssmtp yes
=head1 BUGS
- Should probably handle auth-cram-md5 as well. However, this requires
access to the plain text password. We could store a separate database
of passwords purely for SMTP AUTH, for example as an optional
SMTPAuthPassword property of an account in the esmith::AccountsDB;
=head1 DESCRIPTION
This plugin implements an authentication plugin using Bruce Guenther's
Credential Validation Module (http://untroubled.org/cvm).
=head1 AUTHOR
Copyright 2005 Gordon Rowell <[email protected]>
This software is free software and may be distributed under the same
terms as qpsmtpd itself.
=head1 VERSION
Version $Id: auth_cvm_unix_local,v 1.1 2005/06/09 22:50:06 gordonr Exp gordonr $
=cut
use strict;
use warnings;
use Qpsmtpd::Constants;
use Socket;
use constant SMTP_PORT => getservbyname("smtp", "tcp") || 25;
use constant SSMTP_PORT => getservbyname("ssmtp", "tcp") || 465;
sub register {
my ($self, $qp, %arg) = @_;
unless ($arg{cvm_socket}) {
$self->log(LOGERROR, "skip: requires cvm_socket argument");
return 0;
}
$self->{_args} = {%arg};
$self->{_enable_smtp} = $arg{enable_smtp} || 'no';
$self->{_enable_ssmtp} = $arg{enable_ssmtp} || 'yes';
my $port = $ENV{PORT} || SMTP_PORT;
if ($arg{enable_smtp} ne 'yes' && ($port == SMTP_PORT || $port == 587)) {
$self->log(LOGDEBUG, "skip: enable_smtp=no");
return 0;
}
if ($port == SSMTP_PORT && $arg{enable_ssmtp} ne 'yes') {
$self->log(LOGDEBUG, "skip: enable_ssmtp=no");
return 0;
};
if ($arg{cvm_socket} =~ /^([\w\/.-]+)$/) {
$self->{_cvm_socket} = $1;
}
unless (-S $self->{_cvm_socket}) {
$self->log(LOGERROR, "skip: cvm_socket missing or not usable");
return 0;
}
$self->register_hook("auth-plain", "authcvm_plain");
$self->register_hook("auth-login", "authcvm_plain");
#$self->register_hook("auth-cram-md5", "authcvm_hash");
}
sub authcvm_plain {
my ($self, $transaction, $method, $user, $passClear, $passHash, $ticket) =
@_;
if ($user =~ /\x00/) {
$self->log(LOGERROR, "deny: invalid username");
return DENY, "authcvm, invalid username";
};
socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or do {
$self->log(LOGERROR, "skip: socket creation attempt for: $user");
return DENY, "authcvm";
};
# DENY, really? Should this plugin return a DENY when it cannot connect
# to the cvs socket? I'd expect such a failure to return DECLINED, so
# any other auth plugins could take a stab at authenticating the user
connect(SOCK, sockaddr_un($self->{_cvm_socket})) or do {
$self->log(LOGERROR, "skip: socket connection attempt for: $user");
return DENY, "authcvm, connection failed";
};
my $o = select(SOCK);
$| = 1;
select($o);
my ($u, $host) = split(/\@/, $user);
$host ||= "localhost";
print SOCK "\001$u\000$host\000$passClear\000\000";
shutdown SOCK, 1; # tell remote we're finished
my $ret = <SOCK>;
my ($s) = unpack("C", $ret);
if (!defined $s) {
$self->log(LOGERROR, "skip: no response from cvm for $user");
return DECLINED;
}
if ($s == 0) {
$self->log(LOGINFO, "pass: authentication for: $user");
return OK, "auth success for $user";
}
if ($s == 100) {
$self->log(LOGINFO, "fail: authentication failure for: $user");
return DENY, 'auth failure (100)';
}
$self->log(LOGERROR, "skip: unknown response from cvm for $user");
return DECLINED, "unknown result code ($s)";
}