Re: [Exim] [PATCH] ssmtp (old-style SSL) support for exim 3.…

Top Page
Delete this message
Reply to this message
Author: Alexander Sabourenkov
Date:  
To: exim-users
Subject: Re: [Exim] [PATCH] ssmtp (old-style SSL) support for exim 3.3x viainetd for old style SSL MTAs ...
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')


--