s4-gensec Don't upgrade all DIGEST-MD5 connections to seal
[kai/samba.git] / source4 / auth / gensec / cyrus_sasl.c
index 2cb078ff36e4ab706ecc1188ce2b0d9552a7d0ae..c95bae91fe5d0032ff3337be875bdc6167cf476f 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "auth/auth.h"
-#include "lib/socket/socket.h"
+#include "lib/tsocket/tsocket.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_proto.h"
 #include <sasl/sasl.h>
 
 struct gensec_sasl_state {
        sasl_conn_t *conn;
        int step;
+       bool wrap;
 };
 
 static NTSTATUS sasl_nt_status(int sasl_ret) 
@@ -100,7 +102,7 @@ static int gensec_sasl_get_password(sasl_conn_t *conn, void *context, int id,
                return SASL_NOMEM;
        }
        secret->len = strlen(password);
-       safe_strcpy(secret->data, password, secret->len+1);
+       safe_strcpy((char*)secret->data, password, secret->len+1);
        *psecret = secret;
        return SASL_OK;
 }
@@ -108,7 +110,7 @@ static int gensec_sasl_get_password(sasl_conn_t *conn, void *context, int id,
 static int gensec_sasl_dispose(struct gensec_sasl_state *gensec_sasl_state)
 {
        sasl_dispose(&gensec_sasl_state->conn);
-       return 0;
+       return SASL_OK;
 }
 
 static NTSTATUS gensec_sasl_client_start(struct gensec_security *gensec_security)
@@ -116,15 +118,15 @@ static NTSTATUS gensec_sasl_client_start(struct gensec_security *gensec_security
        struct gensec_sasl_state *gensec_sasl_state;
        const char *service = gensec_get_target_service(gensec_security);
        const char *target_name = gensec_get_target_hostname(gensec_security);
-       struct socket_address *local_socket_addr = gensec_get_my_addr(gensec_security);
-       struct socket_address *remote_socket_addr = gensec_get_peer_addr(gensec_security);
+       const struct tsocket_address *tlocal_addr = gensec_get_local_address(gensec_security);
+       const struct tsocket_address *tremote_addr = gensec_get_remote_address(gensec_security);
        char *local_addr = NULL;
        char *remote_addr = NULL;
        int sasl_ret;
 
        sasl_callback_t *callbacks;
 
-       gensec_sasl_state = talloc(gensec_security, struct gensec_sasl_state);
+       gensec_sasl_state = talloc_zero(gensec_security, struct gensec_sasl_state);
        if (!gensec_sasl_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -152,18 +154,18 @@ static NTSTATUS gensec_sasl_client_start(struct gensec_security *gensec_security
 
        gensec_security->private_data = gensec_sasl_state;
 
-       if (local_socket_addr) {
-               local_addr = talloc_asprintf(gensec_sasl_state, 
-                                            "%s;%d",
-                                            local_socket_addr->addr, 
-                                            local_socket_addr->port);
+       if (tlocal_addr) {
+               local_addr = talloc_asprintf(gensec_sasl_state,
+                               "%s;%d",
+                               tsocket_address_inet_addr_string(tlocal_addr, gensec_sasl_state),
+                               tsocket_address_inet_port(tlocal_addr));
        }
 
-       if (remote_socket_addr) {
-               remote_addr = talloc_asprintf(gensec_sasl_state, 
-                                            "%s;%d",
-                                            remote_socket_addr->addr, 
-                                            remote_socket_addr->port);
+       if (tremote_addr) {
+               remote_addr = talloc_asprintf(gensec_sasl_state,
+                               "%s;%d",
+                               tsocket_address_inet_addr_string(tremote_addr, gensec_sasl_state),
+                               tsocket_address_inet_port(tremote_addr));
        }
        gensec_sasl_state->step = 0;
 
@@ -172,26 +174,27 @@ static NTSTATUS gensec_sasl_client_start(struct gensec_security *gensec_security
                                   local_addr, remote_addr, callbacks, 0,
                                   &gensec_sasl_state->conn);
        
-       if (sasl_ret == SASL_OK || sasl_ret == SASL_CONTINUE) {
+       if (sasl_ret == SASL_OK) {
                sasl_security_properties_t props;
                talloc_set_destructor(gensec_sasl_state, gensec_sasl_dispose);
-
+               
                ZERO_STRUCT(props);
                if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
                        props.min_ssf = 1;
+                       props.max_ssf = 1;
+                       props.maxbufsize = 65536;
+                       gensec_sasl_state->wrap = true;
                }
                if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
                        props.min_ssf = 40;
-               }
-               
-               props.max_ssf = UINT_MAX;
-               props.maxbufsize = 65536;
-               sasl_ret = sasl_setprop(gensec_sasl_state->conn, SASL_SEC_PROPS, &props);
-               if (sasl_ret != SASL_OK) {
-                       return sasl_nt_status(sasl_ret);
+                       props.max_ssf = UINT_MAX;
+                       props.maxbufsize = 65536;
+                       gensec_sasl_state->wrap = true;
                }
 
-       } else {
+               sasl_ret = sasl_setprop(gensec_sasl_state->conn, SASL_SEC_PROPS, &props);
+       }
+       if (sasl_ret != SASL_OK) {
                DEBUG(1, ("GENSEC SASL: client_new failed: %s\n", sasl_errdetail(gensec_sasl_state->conn)));
        }
        return sasl_nt_status(sasl_ret);
@@ -212,8 +215,9 @@ static NTSTATUS gensec_sasl_update(struct gensec_security *gensec_security,
                sasl_ret = sasl_client_start(gensec_sasl_state->conn, gensec_security->ops->sasl_name, 
                                             NULL, &out_data, &out_len, &mech);
        } else {
-               sasl_ret = sasl_client_step(gensec_sasl_state->conn, 
-                                           in.data, in.length, NULL, &out_data, &out_len);
+               sasl_ret = sasl_client_step(gensec_sasl_state->conn,
+                                           (char*)in.data, in.length, NULL,
+                                           &out_data, &out_len);
        }
        if (sasl_ret == SASL_OK || sasl_ret == SASL_CONTINUE) {
                *out = data_blob_talloc(out_mem_ctx, out_data, out_len);
@@ -236,8 +240,9 @@ static NTSTATUS gensec_sasl_unwrap_packets(struct gensec_security *gensec_securi
        const char *out_data;
        unsigned int out_len;
 
-       int sasl_ret = sasl_decode(gensec_sasl_state->conn, 
-                                  in->data, in->length, &out_data, &out_len);
+       int sasl_ret = sasl_decode(gensec_sasl_state->conn,
+                                  (char*)in->data, in->length, &out_data,
+                                  &out_len);
        if (sasl_ret == SASL_OK) {
                *out = data_blob_talloc(out_mem_ctx, out_data, out_len);
                *len_processed = in->length;
@@ -247,6 +252,7 @@ static NTSTATUS gensec_sasl_unwrap_packets(struct gensec_security *gensec_securi
        return sasl_nt_status(sasl_ret);
 
 }
+
 static NTSTATUS gensec_sasl_wrap_packets(struct gensec_security *gensec_security, 
                                        TALLOC_CTX *out_mem_ctx, 
                                        const DATA_BLOB *in, 
@@ -258,8 +264,9 @@ static NTSTATUS gensec_sasl_wrap_packets(struct gensec_security *gensec_security
        const char *out_data;
        unsigned int out_len;
 
-       int sasl_ret = sasl_encode(gensec_sasl_state->conn, 
-                                  in->data, in->length, &out_data, &out_len);
+       int sasl_ret = sasl_encode(gensec_sasl_state->conn,
+                                  (char*)in->data, in->length, &out_data,
+                                  &out_len);
        if (sasl_ret == SASL_OK) {
                *out = data_blob_talloc(out_mem_ctx, out_data, out_len);
                *len_processed = in->length;
@@ -270,33 +277,41 @@ static NTSTATUS gensec_sasl_wrap_packets(struct gensec_security *gensec_security
 }
 
 /* Try to figure out what features we actually got on the connection */
-static BOOL gensec_sasl_have_feature(struct gensec_security *gensec_security, 
+static bool gensec_sasl_have_feature(struct gensec_security *gensec_security, 
                                     uint32_t feature) 
 {
        struct gensec_sasl_state *gensec_sasl_state = talloc_get_type(gensec_security->private_data,
                                                                      struct gensec_sasl_state);
        sasl_ssf_t ssf;
-       int sasl_ret = sasl_getprop(gensec_sasl_state->conn, SASL_SSF, &ssf);
+       int sasl_ret;
+
+       /* If we did not elect to wrap, then we have neither sign nor seal, no matter what the SSF claims */
+       if (!gensec_sasl_state->wrap) {
+               return false;
+       }
+       
+       sasl_ret = sasl_getprop(gensec_sasl_state->conn, SASL_SSF,
+                       (const void**)&ssf);
        if (sasl_ret != SASL_OK) {
-               return False;
+               return false;
        }
        if (feature & GENSEC_FEATURE_SIGN) {
                if (ssf == 0) {
-                       return False;
+                       return false;
                }
                if (ssf >= 1) {
-                       return True;
+                       return true;
                }
        }
        if (feature & GENSEC_FEATURE_SEAL) {
                if (ssf <= 1) {
-                       return False;
+                       return false;
                }
                if (ssf > 1) {
-                       return True;
+                       return true;
                }
        }
-       return False;
+       return false;
 }
 
 /* This could in theory work with any SASL mech */
@@ -308,46 +323,47 @@ static const struct gensec_security_ops gensec_sasl_security_ops = {
        .wrap_packets     = gensec_sasl_wrap_packets,
        .unwrap_packets   = gensec_sasl_unwrap_packets,
        .have_feature     = gensec_sasl_have_feature,
-       .enabled          = False,
+       .enabled          = true,
+       .priority         = GENSEC_SASL
 };
 
-int gensec_sasl_log(void *context, 
+static int gensec_sasl_log(void *context, 
                    int sasl_log_level,
                    const char *message) 
 {
-       int debug_level;
+       int dl;
        switch (sasl_log_level) {
        case SASL_LOG_NONE:
-               debug_level = 0;
+               dl = 0;
                break;
        case SASL_LOG_ERR:
-               debug_level = 1;
+               dl = 1;
                break;
        case SASL_LOG_FAIL:
-               debug_level = 2;
+               dl = 2;
                break;
        case SASL_LOG_WARN:
-               debug_level = 3;
+               dl = 3;
                break;
        case SASL_LOG_NOTE:
-               debug_level = 5;
+               dl = 5;
                break;
        case SASL_LOG_DEBUG:
-               debug_level = 10;
+               dl = 10;
                break;
        case SASL_LOG_TRACE:
-               debug_level = 11;
+               dl = 11;
                break;
 #if DEBUG_PASSWORD
        case SASL_LOG_PASS:
-               debug_level = 100;
+               dl = 100;
                break;
 #endif
        default:
-               debug_level = 0;
+               dl = 0;
                break;
        }
-       DEBUG(debug_level, ("gensec_sasl: %s\n", message));
+       DEBUG(dl, ("gensec_sasl: %s\n", message));
 
        return SASL_OK;
 }
@@ -355,8 +371,11 @@ int gensec_sasl_log(void *context,
 NTSTATUS gensec_sasl_init(void)
 {
        NTSTATUS ret;
-       int sasl_ret, i;
+       int sasl_ret;
+#if 0
+       int i;
        const char **sasl_mechs;
+#endif
        
        static const sasl_callback_t callbacks[] = {
                { 
@@ -398,7 +417,7 @@ NTSTATUS gensec_sasl_init(void)
                if (oldmech) {
                        continue;
                }
-               newmech = talloc(NULL, struct gensec_security_ops);
+               newmech = talloc(talloc_autofree_context(), struct gensec_security_ops);
                if (!newmech) {
                        return NT_STATUS_NO_MEMORY;
                }