This is a multi-part message in MIME format.
--
Suresh Ramasubramanian wrote:
> I'd certainly be interested ... tried building a port of exim 4.02 -
> with AUTH_PWCHECK=yes hardcoded into src/EDITME ... sheldon's port is
> still at 4.01
>
> It is trivial to build myself a port of 4.02 from sheldon's exim-devel
> port, which I did (and it works perfectly) ... but what else did you do?
>
> As it is, src/auths/call_pwcheck.c in exim 4.02 says -
>
> : /* This module is reserved to contain functions that call the
> : Cyrus-SASL pwcheck authentication daemon. However, it is currently
> : non-functional, and won't ever be called (it is never referenced!). */
Yep, in raw 4.02 it's a placeholder at most.
[skip]
> 2002-04-02 23:48:05 Authentication failed for
> cm61-10-209-175.hkcable.com.hk (consultant.com) [61.10.209.175]: 435
> Unable to authenticate at present (set_id=suresh): unknown condition
> "pwcheck"
>
> in an endless loop till I break it by stopping mozilla from trying to
> send the mail (hitting cancel). So, just what did you do?
>
I've forward ported my patch for 3.33 to 4.02 .
It requires SASL's pwcheck daemon running at the machine. Mine's from 1.5whatewer
version, but i think later version will work fine. Just untar the SASL source,
do a ./configure --with-pwcheck , cd into src/pwcheck and make.
You will need to create a directory named /var/pwcheck and give exim user r-x permissions
to it. That's where the pwcheck daemon will create its socket. The location can
be changed, it's hardcoded in exim-4.02/src/auths/pwcheck.c and AFAIK there's a
switch in SASL's configure for this.
Also, find the patch attached. It's against 4.02 sources as found at the main ftp.
After that, here's exim authenticator config that i use:
-------8<----------
begin authenticators
login:
driver = plaintext
public_name = LOGIN
server_prompts = "Username:: : Password::"
server_condition = "${if pwcheck{$1:$2}{1}{0}}"
server_set_id = $1
plainns:
driver = plaintext
public_name = PLAIN
server_condition = "${if pwcheck{$2:$3}{1}{0}}"
server_set_id = $2
---------->8--------
That's it.
If there's any chance of this to be included into exim distribution, I'll tidy up the code
and move the location of pwcheck socket into Local/Makefile defines.
PS. while forward-porting, I've somewhat changed the code which calls condition functions
for pwcheck (added), pam and raduis. While I tried to leave the functionality intact, I use
neither of later two, so I can't be sure if they still work. Bugreports and fixes are welcome.
./lxnt
--
diff -N -u -r exim-4.02/scripts/MakeLinks exim-4.02pwc/scripts/MakeLinks
--- exim-4.02/scripts/MakeLinks Mon Mar 25 14:09:42 2002
+++ exim-4.02pwc/scripts/MakeLinks Fri Mar 29 15:34:30 2002
@@ -145,6 +145,8 @@
ln -s ../../src/auths/auth-spa.h auth-spa.h
ln -s ../../src/auths/spa.c spa.c
ln -s ../../src/auths/spa.h spa.h
+ln -s ../../src/auths/pwcheck.c pwcheck.c
+ln -s ../../src/auths/pwcheck.h pwcheck.h
cd ..
# The basic source files for Exim and utilities. NB local_scan.h gets linked,
diff -N -u -r exim-4.02/src/EDITME exim-4.02pwc/src/EDITME
--- exim-4.02/src/EDITME Mon Mar 25 14:09:42 2002
+++ exim-4.02pwc/src/EDITME Fri Mar 29 15:33:09 2002
@@ -446,6 +446,14 @@
# RADIUS_CONFIG_FILE=/etc/radiusclient/radiusclient.conf
+#------------------------------------------------------------------------------
+# Support for authentication via SASL pwcheck daemon is also available.
+# There is no need to install SASL on your system. You can only say
+# ./configure --with-pwcheck, then cd to pwcheck dir with sources, say make
+# and install pwcheck somewhere to be run at reboot. Make sure to
+# mkdir /var/pwcheck and chown it to exim's user and group.
+
+# SUPPORT_PWCHECK=yes
#------------------------------------------------------------------------------
# TCP wrappers: If you want to use tcpwrappers from within Exim, uncomment
diff -N -u -r exim-4.02/src/auths/Makefile exim-4.02pwc/src/auths/Makefile
--- exim-4.02/src/auths/Makefile Mon Mar 25 14:09:42 2002
+++ exim-4.02pwc/src/auths/Makefile Fri Mar 29 15:10:45 2002
@@ -7,7 +7,7 @@
OBJ = b64encode.o b64decode.o call_pam.o call_pwcheck.o call_radius.o \
xtextencode.o xtextdecode.o get_data.o md5.o cram_md5.o plaintext.o \
- auth-spa.o spa.o
+ auth-spa.o spa.o pwcheck.o
auths.a: $(OBJ)
/bin/rm -f auths.a
@@ -32,5 +32,6 @@
cram_md5.o: $(HDRS) cram_md5.c cram_md5.h
plaintext.o: $(HDRS) plaintext.c plaintext.h
auth-spa.o: $(HDRS) spa.c spa.h
+pwcheck.o: $(HDRS) pwcheck.c
# End
diff -N -u -r exim-4.02/src/auths/call_pwcheck.c exim-4.02pwc/src/auths/call_pwcheck.c
--- exim-4.02/src/auths/call_pwcheck.c Mon Mar 25 14:09:42 2002
+++ exim-4.02pwc/src/auths/call_pwcheck.c Fri Mar 29 18:14:00 2002
@@ -6,6 +6,7 @@
/* See the file NOTICE for conditions of use and distribution. */
#include "../exim.h"
+#include "pwcheck.h"
/* This module is reserved to contain functions that call the Cyrus-SASL
pwcheck authentication daemon. However, it is currently non-functional, and
@@ -34,6 +35,7 @@
auth_call_pwcheck(uschar *s, uschar **errptr)
{
uschar *pw = Ustrrchr(s, ':');
+int rc;
if (pw == NULL)
{
@@ -43,10 +45,6 @@
*pw++ = 0;
-return FAIL; /* Just to keep the compiler happy */
-
-
-/*****
rc = pwcheck_verify_password(s, pw, NULL);
DEBUG(D_auth) debug_printf("pwcheck: user=%s password=%s rc=%d\n", s, pw, rc);
@@ -55,7 +53,6 @@
*errptr = US"pwcheck authentication failed";
return FAIL;
-****/
}
diff -N -u -r exim-4.02/src/auths/pwcheck.c exim-4.02pwc/src/auths/pwcheck.c
--- exim-4.02/src/auths/pwcheck.c Thu Jan 1 03:00:00 1970
+++ exim-4.02pwc/src/auths/pwcheck.c Fri Mar 29 15:43:57 2002
@@ -0,0 +1,131 @@
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <strings.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include "../exim.h"
+#include "pwcheck.h"
+
+ /* taken from cyrus-sasl file checkpw.c */
+ /*
+ * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
+ * until all the data is written out or an error occurs.
+ */
+ static int retry_writev(int fd, struct iovec *iov, int iovcnt)
+ {
+ int n;
+ int i;
+ int written = 0;
+ static int iov_max =
+ #ifdef MAXIOV
+ MAXIOV
+ #else
+ #ifdef IOV_MAX
+ IOV_MAX
+ #else
+ 8192
+ #endif
+ #endif
+ ;
+
+ for (;;) {
+ while (iovcnt && iov[0].iov_len == 0) {
+ iov++;
+ iovcnt--;
+ }
+
+ if (!iovcnt) return written;
+
+ n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
+ if (n == -1) {
+ if (errno == EINVAL && iov_max > 10) {
+ iov_max /= 2;
+ continue;
+ }
+ if (errno == EINTR) continue;
+ return -1;
+ }
+
+ written += n;
+
+ for (i = 0; i < iovcnt; i++) {
+ if (iov[i].iov_len > n) {
+ iov[i].iov_base = (char *)iov[i].iov_base + n;
+ iov[i].iov_len -= n;
+ break;
+ }
+ n -= iov[i].iov_len;
+ iov[i].iov_len = 0;
+ }
+
+ if (i == iovcnt) return written;
+ }
+ }
+
+
+ /* taken from cyrus-sasl file checkpw.c */
+ /* pwcheck daemon-authenticated login */
+ int pwcheck_verify_password(const char *userid,
+ const char *passwd,
+ const char **reply)
+ {
+ int s;
+ struct sockaddr_un srvaddr;
+ int r;
+ struct iovec iov[10];
+ static char response[1024];
+ int start, n;
+ char pwpath[1024];
+
+ if (reply) { *reply = NULL; }
+
+ /*if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
+ */
+ strcpy(pwpath, "/var/pwcheck");
+ strcat(pwpath, "/pwcheck");
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) return errno;
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
+ r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ if (reply) { *reply = "cannot connect to pwcheck server"; }
+ return PWCHECK_BAD;
+ }
+
+ iov[0].iov_base = (char *)userid;
+ iov[0].iov_len = strlen(userid)+1;
+ iov[1].iov_base = (char *)passwd;
+ iov[1].iov_len = strlen(passwd)+1;
+
+ retry_writev(s, iov, 2);
+
+ start = 0;
+ while (start < sizeof(response) - 1) {
+ n = read(s, response+start, sizeof(response) - 1 - start);
+ if (n < 1) break;
+ start += n;
+ }
+
+ close(s);
+
+ if (start > 1 && !strncmp(response, "OK", 2)) {
+ return PWCHECK_OK;
+ }
+
+ response[start] = '\0';
+ if (reply) { *reply = response; }
+ return PWCHECK_BAD;
+ }
diff -N -u -r exim-4.02/src/auths/pwcheck.h exim-4.02pwc/src/auths/pwcheck.h
--- exim-4.02/src/auths/pwcheck.h Thu Jan 1 03:00:00 1970
+++ exim-4.02pwc/src/auths/pwcheck.h Fri Mar 29 15:17:15 2002
@@ -0,0 +1,4 @@
+#ifndef PWCHECK_OK
+ #define PWCHECK_OK 1
+ #define PWCHECK_BAD 0
+#endif
diff -N -u -r exim-4.02/src/config.h.defaults exim-4.02pwc/src/config.h.defaults
--- exim-4.02/src/config.h.defaults Mon Mar 25 14:09:43 2002
+++ exim-4.02pwc/src/config.h.defaults Fri Mar 29 17:58:31 2002
@@ -95,6 +95,7 @@
#define SUPPORT_PAM
#define SUPPORT_TLS
#define SUPPORT_TRANSLATE_IP_ADDRESS
+#define SUPPORT_PWCHECK
#define TIMEZONE_DEFAULT
diff -N -u -r exim-4.02/src/expand.c exim-4.02pwc/src/expand.c
--- exim-4.02/src/expand.c Mon Mar 25 14:09:43 2002
+++ exim-4.02pwc/src/expand.c Fri Mar 29 18:12:15 2002
@@ -920,8 +920,13 @@
pam: does PAM authentication
radius: does RADIUS authentication
ldapauth: does LDAP authentication
+ pwcheck: does SASL pcwcheck auth
*/
+#ifndef SUPPORT_PWCHECK
+#warning SUPPORT_PWCHECK UNDEFINED!!!! HELP!!! HELP!!!
+#endif
+
else if (Ustrcmp(name, "exists") == 0
#ifdef SUPPORT_PAM
|| Ustrcmp(name, "pam") == 0
@@ -932,6 +937,9 @@
#ifdef LOOKUP_LDAP
|| Ustrcmp(name, "ldapauth") == 0
#endif
+ #ifdef SUPPORT_PWCHECK
+ || Ustrcmp(name, "pwcheck") == 0
+ #endif
)
{
uschar *sub;
@@ -956,9 +964,9 @@
else /* Various authentication tests - all optionally compiled */
{
#ifdef SUPPORT_PAM
- if (name[0] == 'p')
+ if ((name[0] == 'p') && (name[1] == 'a'))
rc = auth_call_pam(sub, &expand_string_message);
- #if defined(RADIUS_CONFIG_FILE) || defined(LOOKUP_LDAP)
+ #if defined(RADIUS_CONFIG_FILE) || defined(LOOKUP_LDAP) || defined(SUPPORT_PWCHECK)
else
#endif
#endif /* SUPPORT_PAM */
@@ -966,10 +974,21 @@
#ifdef RADIUS_CONFIG_FILE
if (name[0] == 'r')
rc = auth_call_radius(sub, &expand_string_message);
- #if defined(LOOKUP_LDAP)
+ #if defined(LOOKUP_LDAP) || defined(SUPPORT_PWCHECK)
else
#endif
#endif /* RADIUS_CONFIG_FILE */
+
+ #ifdef SUPPORT_PWCHECK
+ if ((name[0] == 'p') && (name[1] == 'w')) {
+ DEBUG(D_auth) debug_printf("\nCalling auth_call_pwcheck() with '%s'",sub);
+ rc = auth_call_pwcheck(sub, &expand_string_message);
+ DEBUG(D_auth) debug_printf(" returned with %d\n",rc);
+ }
+ #if defined(LOOKUP_LDAP)
+ else
+ #endif
+ #endif /* SUPPORT_PWCHECK */
#ifdef LOOKUP_LDAP
if (name[0] == 'l')
--