Merge in changes from the 1.1 branch.
authorKen Hornstein <kenh@pobox.com>
Fri, 5 Sep 2003 21:07:49 +0000 (21:07 +0000)
committerKen Hornstein <kenh@pobox.com>
Fri, 5 Sep 2003 21:07:49 +0000 (21:07 +0000)
.cvsignore
configure.in
docs/FAQ
docs/README.SASL [new file with mode: 0644]
docs/README.developers
mts/smtp/smtp.c
uip/popsbr.c

index 2327092..9d5e65d 100644 (file)
@@ -1,3 +1,4 @@
+autom4te.cache
 configure
 config.h.in
 stamp-h.in
index f029fd6..c3fb81a 100644 (file)
@@ -638,8 +638,8 @@ if test x"$with_cyrus_sasl" != x -a x"$with_cyrus_sasl" != x"no"; then
   fi
   save_LDFLAGS="$LDFLAGS"
   LDFLAGS="$LDFLAGS $SASL_LIBS"
-  AC_CHECK_LIB(sasl, sasl_client_new,
-    [SASL_LIBS="$SASL_LIBS -lsasl"],
+  AC_CHECK_LIB(sasl2, sasl_client_new,
+    [SASL_LIBS="$SASL_LIBS -lsasl2"],
     [AC_MSG_ERROR(Cyrus SASL library not found)])
   LDFLAGS="$save_LDFLAGS"
 fi
index 99f6d1f..0bcd62f 100644 (file)
--- a/docs/FAQ
+++ b/docs/FAQ
 
    Richard Coleman (coleman@math.gatech.edu) started the nmh project.
    After he grew too busy to continue maintaining it, it was handed off
-   to the net at large. Doug Morris (doug@mhost.com) is hosting the
-   mailing lists, web pages, and CVS repository for nmh now.
+   to the net at large. Doug Morris (doug@mhost.com) hosted the web
+   site and mailing lists, web pages, and CVS repository for a long
+   time.  More recently, the CVS repository has moved to Savannah
+   (http://savannah.gnu.org/projects/nmh) and Ken Hornstein 
+   (kenh@pobox.com) is the project maintainer.
 
 4) Why did Richard start the nmh project?
 
 7) Where do I get nmh?
 
     The latest version of nmh is available at
-    ftp://ftp.mhost.com/pub/nmh/nmh.tar.gz
+    http://savannah.gnu.org/download/nmh
 
 8) Where is the nmh web page?
 
     The nmh home page is located at
-    http://www.mhost.com/nmh/
+    http://savannah.gnu.org/projects/nmh/
 
 9) Where is the nmh mailing list?
 
diff --git a/docs/README.SASL b/docs/README.SASL
new file mode 100644 (file)
index 0000000..3dd7623
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# README.SASL - Readme about SASL support in nmh
+#
+# $Id$
+#
+
+SASL is short for the Simple Authentication and Security Layer.  Is is
+a framework for adding authentication and encryption to network protocols.
+It is described in IETF RFC 2222.
+
+This release of nmh supports SASL for POP and SMTP.  The SASL support
+is implemented using the Cyrus-SASL library.  This library can be found
+at ftp://ftp.andrew.cmu.edu/pub/cyrus-mail.  Obviously, SASL support only
+works if you use --enable-pop and the SMTP mail transport.
+
+This release of NMH only supports "Version 2" of the Cyrus SASL library.
+It should work with any newer Cyrus SASL release, but it was tested with
+Cyrus SASL 2.1.12.  In particular, the CRAM-MD5 and GSSAPI (Kerberos 5)
+mechanisms were tested.
+
+Currently, security layers ("encryption" in SASL-speak) are only supported
+for POP.  This means that if your POP server _and_ the selected GSSAPI
+mechanism supports it, POP communications will be encrypted.  Currently
+SMTP does NOT support security layers; this may be added in a future
+release.
+
+If you are curious as to whether or not your communications are actually
+encrypted or not, you can use the -snoop flag to the POP utilities.
+Communication that is encrypted is preceeded by an (*).
+
+If you would like to use the GSSAPI SASL mechanism (Kerberos V), you
+should read very carefully the documentation that comes with
+Cyrus-SASL, specifically the GSSAPI documentation.  Getting the GSSAPI
+plugin to work correctly with SASL can be "interesting" to say the least.
index fe31352..20b6452 100644 (file)
@@ -17,7 +17,8 @@ autoconf files
 
 If you wish to change the `configure' script or its related files, you'll need
 to first install GNU m4, available from <ftp://ftp.gnu.org/pub/gnu/m4/> and then
-GNU autoconf (<ftp://ftp.gnu.org/pub/gnu/autoconf/>).
+GNU autoconf (<ftp://ftp.gnu.org/pub/gnu/autoconf/>).  Nmh is currently using
+a minimum of autoconf 2.54.
 
 Most of the configure-related files are automatically generated.  The only files
 you should need to manually edit are acconfig.h and configure.in.  Don't, for
@@ -25,41 +26,14 @@ instance, edit config.h.in.  Though it is an input file from the point of view
 of the users (and the configure script) it is an output file from the point of
 view of the developers (and the autoconf script).
 
-If you do change acconfig.h or configure.in and want to `cvs commit' them, be
-sure to regenerate the output files and commit them as well.  The easiest way to
-regenerate the files is to simply run `make' -- it'll do the necessary calls of
-autoconf and autoheader and will do a `./config.status --recheck', which will
-exercise your new configure script.
-
-When you commit the configure-related files, it's very important to commit them
-in the right order.  The timestamps on the files in the CVS archive are based on
-the current time at the moment they were committed -- the timestamps from the
-local files you commit are not copied over.  If you commit the files in the
-wrong order, you'll cause unnecessary calls of `autoconf' to occur when people
-try to `make' their copies of the latest CVS source.  These people may be
-end-users who don't have any interest in changing the configure-related files
-and don't have autoconf installed.  They'll be unable to make without playing
-around with `touch'.
-
-The correct procedure to commit the configure-related files is:
-
-    % cvs commit acconfig.h aclocal.m4 configure.in
-    % autoheader; autoconf; \date > stamp-h.in
-    % cvs commit config.h.in configure stamp-h.in
-
-The reason for the three-step commit is that configure.in contains the RCS $Id
-keyword, so when you commit it, a new version is written locally.  Therefore,
-the autoconf regeneration should be held off until after the commit, or your
-local stamp-h.in will become out-of-sync with the CVS version (granted, not that
-big a deal).  For the second step, you're doing the same commands as a 
-`make reset' would do, but using that command would require extra configure runs
-to make Makefile be up-to-date.  The reason for the backslash on `date' is in
-case you have `date' aliased in your shell to use a nonstandard format.
-
-If you haven't changed all the files noted above, just commit the ones you have
-changed, in the stated order (for instance, configure.in, then configure and
-stamp-h.in).
+Note that the automatically generated autoconf files (such as config.h.in,
+stamp-h.in, and configure), are NOT kept in CVS.  Thus, when you check out
+a CVS tree, you need to do the following things before you can build
+anything:
 
+       % autoheader
+       % autoconf
+       % date > stamp-h.in
 
 -------------------
 directory structure
index ca56781..5760356 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifdef CYRUS_SASL
 #include <sasl.h>
+#include <saslutil.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -1108,12 +1109,11 @@ no_dice:
 static int
 sm_auth_sasl(char *user, char *mechlist, char *host)
 {
-    int result, status, outlen;
-    unsigned int buflen;
+    int result, status;
+    unsigned int buflen, outlen;
     char *buf, outbuf[BUFSIZ];
     const char *chosen_mech;
     sasl_security_properties_t secprops;
-    sasl_external_properties_t extprops;
     sasl_ssf_t *ssf;
     int *outbufmax;
 
@@ -1166,7 +1166,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
        return NOTOK;
     }
 
-    result = sasl_client_new("smtp", host, NULL, SASL_SECURITY_LAYER, &conn);
+    result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn);
 
     if (result != SASL_OK) {
        sm_ierror("SASL client initialization failed: %s",
@@ -1181,7 +1181,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
     memset(&secprops, 0, sizeof(secprops));
     secprops.maxbufsize = BUFSIZ;
     secprops.max_ssf = 0;      /* XXX change this when we do encryption */
-    memset(&extprops, 0, sizeof(extprops));
 
     result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
 
@@ -1191,21 +1190,13 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
        return NOTOK;
     }
 
-    result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops);
-
-    if (result != SASL_OK) {
-       sm_ierror("SASL external property initialization failed: %s",
-                 sasl_errstring(result, NULL, NULL));
-       return NOTOK;
-    }
-
     /*
      * Start the actual protocol.  Feed the mech list into the library
      * and get out a possible initial challenge
      */
 
-    result = sasl_client_start(conn, mechlist, NULL, NULL, &buf, &buflen,
-                              &chosen_mech);
+    result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf,
+                              &buflen, (const char **) &chosen_mech);
 
     if (result != SASL_OK && result != SASL_CONTINUE) {
        sm_ierror("SASL client start failed: %s",
@@ -1220,7 +1211,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
 
     if (buflen) {
        status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
-       free(buf);
        if (status != SASL_OK) {
            sm_ierror("SASL base64 encode failed: %s",
                      sasl_errstring(status, NULL, NULL));
@@ -1263,7 +1253,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
            outlen = 0;
        } else {
            result = sasl_decode64(sm_reply.text, sm_reply.length,
-                                  outbuf, &outlen);
+                                  outbuf, sizeof(outbuf), &outlen);
        
            if (result != SASL_OK) {
                smtalk(SM_AUTH, "*");
@@ -1273,7 +1263,8 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
            }
        }
 
-       result = sasl_client_step(conn, outbuf, outlen, NULL, &buf, &buflen);
+       result = sasl_client_step(conn, outbuf, outlen, NULL,
+                                 (const char **) &buf, &buflen);
 
        if (result != SASL_OK && result != SASL_CONTINUE) {
            smtalk(SM_AUTH, "*");
@@ -1283,7 +1274,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
        }
 
        status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
-       free(buf);
 
        if (status != SASL_OK) {
            smtalk(SM_AUTH, "*");
@@ -1303,24 +1293,11 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
        return RP_BHST;
 
     /*
-     * Depending on the mechanism, we need to do a FINAL call to
-     * sasl_client_step().  Do that now.
-     */
-
-    result = sasl_client_step(conn, NULL, 0, NULL, &buf, &buflen);
-
-    if (result != SASL_OK) {
-       sm_ierror("SASL final client negotiation failed: %s",
-                 sasl_errstring(result, NULL, NULL));
-       return NOTOK;
-    }
-
-    /*
      * We _should_ have completed the authentication successfully.
      * Get a few properties from the authentication exchange.
      */
 
-    result = sasl_getprop(conn, SASL_MAXOUTBUF, (void **) &outbufmax);
+    result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax);
 
     if (result != SASL_OK) {
        sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
@@ -1330,7 +1307,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
 
     maxoutbuf = *outbufmax;
 
-    result = sasl_getprop(conn, SASL_SSF, (void **) &ssf);
+    result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
 
     sasl_ssf = *ssf;
 
@@ -1390,7 +1367,7 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id,
     }
 
     (*psecret)->len = len;
-    strcpy((*psecret)->data, pass);
+    strcpy((char *) (*psecret)->data, pass);
 /*    free(pass); */
 
     return SASL_OK;
index 577a4b0..685489a 100644 (file)
@@ -27,6 +27,7 @@ extern int  client(char *args, char *protocol, char *service, int rproto,
 
 #ifdef CYRUS_SASL
 # include <sasl.h>
+# include <saslutil.h>
 #endif /* CYRUS_SASL */
 
 #include <h/popsbr.h>
@@ -77,6 +78,7 @@ static sasl_callback_t callbacks[] = {
 #define POP_SASL_CB_N_USER 0
     { SASL_CB_PASS, sasl_get_pass, NULL },
 #define POP_SASL_CB_N_PASS 1
+    { SASL_CB_LOG, NULL, NULL },
     { SASL_CB_LIST_END, NULL, NULL },
 };
 #else /* CYRUS_SASL */
@@ -163,12 +165,11 @@ pop_auth (char *user, char *pass)
 int
 pop_auth_sasl(char *user, char *host, char *mech)
 {
-    int result, status, sasl_capability = 0, outlen;
-    unsigned int buflen;
+    int result, status, sasl_capability = 0;
+    unsigned int buflen, outlen;
     char server_mechs[256], *buf, outbuf[BUFSIZ];
     const char *chosen_mech;
     sasl_security_properties_t secprops;
-    sasl_external_properties_t extprops;
     struct pass_context p_context;
     sasl_ssf_t *ssf;
     int *moutbuf;
@@ -240,7 +241,7 @@ pop_auth_sasl(char *user, char *host, char *mech)
        return NOTOK;
     }
 
-    result = sasl_client_new("pop", host, NULL, SASL_SECURITY_LAYER, &conn);
+    result = sasl_client_new("pop", host, NULL, NULL, NULL, 0, &conn);
 
     if (result != SASL_OK) {
        snprintf(response, sizeof(response), "SASL client initialization "
@@ -255,23 +256,12 @@ pop_auth_sasl(char *user, char *host, char *mech)
     memset(&secprops, 0, sizeof(secprops));
     secprops.maxbufsize = BUFSIZ;
     secprops.max_ssf = UINT_MAX;
-    memset(&extprops, 0, sizeof(extprops));
 
     result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
 
     if (result != SASL_OK) {
        snprintf(response, sizeof(response), "SASL security property "
-                "initialization failed: %s",
-                sasl_errstring(result, NULL, NULL));
-       return NOTOK;
-    }
-
-    result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops);
-
-    if (result != SASL_OK) {
-       snprintf(response, sizeof(response), "SASL external property "
-                "initialization failed: %s",
-                sasl_errstring(result, NULL, NULL));
+                "initialization failed: %s", sasl_errdetail(conn));
        return NOTOK;
     }
 
@@ -280,18 +270,19 @@ pop_auth_sasl(char *user, char *host, char *mech)
      * and get out a possible initial challenge
      */
 
-    result = sasl_client_start(conn, mech ? mech : server_mechs,
-                              NULL, NULL, &buf, &buflen, &chosen_mech);
+    result = sasl_client_start(conn,
+                              (const char *) (mech ? mech : server_mechs),
+                              NULL, (const char **) &buf,
+                              &buflen, &chosen_mech);
 
     if (result != SASL_OK && result != SASL_CONTINUE) {
        snprintf(response, sizeof(response), "SASL client start failed: %s",
-                sasl_errstring(result, NULL, NULL));
+                sasl_errdetail(conn));
        return NOTOK;
     }
 
     if (buflen) {
        status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
-       free(buf);
        if (status != SASL_OK) {
            snprintf(response, sizeof(response), "SASL base64 encode "
                     "failed: %s", sasl_errstring(status, NULL, NULL));
@@ -327,7 +318,7 @@ pop_auth_sasl(char *user, char *host, char *mech)
        }
 
        result = sasl_decode64(response + 2, strlen(response + 2),
-                              outbuf, &outlen);
+                              outbuf, sizeof(outbuf), &outlen);
        
        if (result != SASL_OK) {
            command("*");
@@ -336,17 +327,17 @@ pop_auth_sasl(char *user, char *host, char *mech)
            return NOTOK;
        }
 
-       result = sasl_client_step(conn, outbuf, outlen, NULL, &buf, &buflen);
+       result = sasl_client_step(conn, outbuf, outlen, NULL,
+                                 (const char **) &buf, &buflen);
 
        if (result != SASL_OK && result != SASL_CONTINUE) {
            command("*");
            snprintf(response, sizeof(response), "SASL client negotiaton "
-                    "failed: %s", sasl_errstring(result, NULL, NULL));
+                    "failed: %s", sasl_errdetail(conn));
            return NOTOK;
        }
 
        status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
-       free(buf);
 
        if (status != SASL_OK) {
            command("*");
@@ -367,41 +358,27 @@ pop_auth_sasl(char *user, char *host, char *mech)
        return NOTOK;
 
     /*
-     * Depending on the mechanism, we might need to call sasl_client_step()
-     * one more time.  Do that now.
-     */
-
-    result = sasl_client_step(conn, NULL, 0, NULL, &buf, &buflen);
-
-    if (result != SASL_OK) {
-       snprintf(response, sizeof(response), "SASL final client negotiaton "
-                "failed: %s", sasl_errstring(result, NULL, NULL));
-       return NOTOK;
-    }
-
-    /*
      * We _should_ be okay now.  Get a few properties now that negotiation
      * has completed.
      */
 
-    result = sasl_getprop(conn, SASL_MAXOUTBUF, (void **) &moutbuf);
+    result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &moutbuf);
 
     if (result != SASL_OK) {
        snprintf(response, sizeof(response), "Cannot retrieve SASL negotiated "
-                "output buffer size: %s", sasl_errstring(result, NULL, NULL));
+                "output buffer size: %s", sasl_errdetail(conn));
        return NOTOK;
     }
 
     maxoutbuf = *moutbuf;
 
-    result = sasl_getprop(conn, SASL_SSF, (void **) &ssf);
+    result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
 
     sasl_ssf = *ssf;
 
     if (result != SASL_OK) {
        snprintf(response, sizeof(response), "Cannot retrieve SASL negotiated "
-                "security strength factor: %s",
-                sasl_errstring(result, NULL, NULL));
+                "security strength factor: %s", sasl_errdetail(conn));
        return NOTOK;
     }
 
@@ -461,7 +438,7 @@ sasl_get_pass(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
        return SASL_NOMEM;
 
     (*psecret)->len = len;
-    strcpy((*psecret)->data, pass);
+    strcpy((char *) (*psecret)->data, pass);
 
     return SASL_OK;
 }
@@ -1076,16 +1053,16 @@ putline (char *s, FILE *iop)
        outbuf[sizeof(outbuf) - 3] = '\0';   /* Just in case */
        strcat(outbuf, "\r\n");
 
-       result = sasl_encode(conn, outbuf, strlen(outbuf), &buf, &buflen);
+       result = sasl_encode(conn, outbuf, strlen(outbuf),
+                            (const char **) &buf, &buflen);
 
        if (result != SASL_OK) {
            snprintf(response, sizeof(response), "SASL encoding error: %s",
-                    sasl_errstring(result, NULL, NULL));
+                    sasl_errdetail(conn));
            return NOTOK;
        }
 
        fwrite(buf, buflen, 1, iop);
-       free(buf);
     }
 #endif /* CYRUS_SASL */
 
@@ -1151,11 +1128,12 @@ sasl_fgetc(FILE *f)
 
        } else {
 
-           result = sasl_decode(conn, tmpbuf, cc, &retbuf, &retbufsize);
+           result = sasl_decode(conn, tmpbuf, cc,
+                                (const char **) &retbuf, &retbufsize);
 
            if (result != SASL_OK) {
                snprintf(response, sizeof(response), "Error during SASL "
-                        "decoding: %s", sasl_errstring(result, NULL, NULL));
+                        "decoding: %s", sasl_errdetail(conn));
                return -2;
            }
        }
@@ -1174,8 +1152,6 @@ sasl_fgetc(FILE *f)
     memcpy(buffer, retbuf, retbufsize);
     ptr = buffer + 1;
     cnt = retbufsize - 1;
-    if (sasl_complete)
-       free(retbuf);
 
     return (int) buffer[0];
 }