r23946: add support for NTLMSSP sign and seal
authorStefan Metzmacher <metze@samba.org>
Wed, 18 Jul 2007 08:15:42 +0000 (08:15 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:28:48 +0000 (12:28 -0500)
NOTE: windows servers are broken with sign only...

metze
(This used to be commit 408bb2e6e2171196a2bd314db181d9b124e931a1)

source3/include/ads.h
source3/libads/sasl.c

index 1c02366ed4b636934b2554bb3a26bd550444fcc8..56c70233379fdf3c1162faf542848df6dcbbbd74 100644 (file)
@@ -36,7 +36,7 @@ struct ads_saslwrap_ops {
        const char *name;
        ADS_STATUS (*wrap)(struct ads_struct *, uint8 *buf, uint32 len);
        ADS_STATUS (*unwrap)(struct ads_struct *);
-       ADS_STATUS (*disconnect)(struct ads_struct *);
+       void (*disconnect)(struct ads_struct *);
 };
 
 enum ads_saslwrap_type {
index 94600d72344412998f089c74324db3b3db70d6c6..08a6765e27d1230a69d9b37f6efbcaa90e90c480 100644 (file)
 
 #ifdef HAVE_LDAP
 
+static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
+{
+       struct ntlmssp_state *ntlmssp_state = ads->ldap.wrap_private_data;
+       ADS_STATUS status;
+       NTSTATUS nt_status;
+       DATA_BLOB sig;
+       uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
+
+       /* copy the data to the right location */
+       memcpy(dptr, buf, len);
+
+       /* create the signature and may encrypt the data */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+               nt_status = ntlmssp_seal_packet(ntlmssp_state,
+                                               dptr, len,
+                                               dptr, len,
+                                               &sig);
+       } else {
+               nt_status = ntlmssp_sign_packet(ntlmssp_state,
+                                               dptr, len,
+                                               dptr, len,
+                                               &sig);
+       }
+       status = ADS_ERROR_NT(nt_status);
+       if (!ADS_ERR_OK(status)) return status;
+
+       /* copy the signature to the right location */
+       memcpy(ads->ldap.out.buf + 4,
+              sig.data, NTLMSSP_SIG_SIZE);
+
+       data_blob_free(&sig);
+
+       /* set how many bytes must be written to the underlying socket */
+       ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
+
+       return ADS_SUCCESS;
+}
+
+static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
+{
+       struct ntlmssp_state *ntlmssp_state = ads->ldap.wrap_private_data;
+       ADS_STATUS status;
+       NTSTATUS nt_status;
+       DATA_BLOB sig;
+       uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
+       uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
+
+       /* wrap the signature into a DATA_BLOB */
+       sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
+
+       /* verify the signature and maybe decrypt the data */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+               nt_status = ntlmssp_unseal_packet(ntlmssp_state,
+                                                 dptr, dlen,
+                                                 dptr, dlen,
+                                                 &sig);
+       } else {
+               nt_status = ntlmssp_check_packet(ntlmssp_state,
+                                                dptr, dlen,
+                                                dptr, dlen,
+                                                &sig);
+       }
+       status = ADS_ERROR_NT(nt_status);
+       if (!ADS_ERR_OK(status)) return status;
+
+       /* set the amount of bytes for the upper layer and set the ofs to the data */
+       ads->ldap.in.left       = dlen;
+       ads->ldap.in.ofs        = 4 + NTLMSSP_SIG_SIZE;
+
+       return ADS_SUCCESS;
+}
+
+static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
+{
+       struct ntlmssp_state *ntlmssp_state = ads->ldap.wrap_private_data;
+
+       ntlmssp_end(&ntlmssp_state);
+
+       ads->ldap.wrap_ops = NULL;
+       ads->ldap.wrap_private_data = NULL;
+}
+
+static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
+       .name           = "ntlmssp",
+       .wrap           = ads_sasl_ntlmssp_wrap,
+       .unwrap         = ads_sasl_ntlmssp_unwrap,
+       .disconnect     = ads_sasl_ntlmssp_disconnect
+};
+
 /* 
    perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
    we fit on one socket??)
@@ -35,6 +124,7 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
        int rc;
        NTSTATUS nt_status;
        int turn = 1;
+       uint32 features = 0;
 
        struct ntlmssp_state *ntlmssp_state;
 
@@ -53,6 +143,28 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
                return ADS_ERROR_NT(nt_status);
        }
 
+       switch (ads->ldap.wrap_type) {
+       case ADS_SASLWRAP_TYPE_SEAL:
+               features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
+               break;
+       case ADS_SASLWRAP_TYPE_SIGN:
+               if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
+                       features = NTLMSSP_FEATURE_SIGN;
+               } else {
+                       /*
+                        * windows servers are broken with sign only,
+                        * so we need to use seal here too
+                        */
+                       features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
+                       ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
+               }
+               break;
+       case ADS_SASLWRAP_TYPE_PLAIN:
+               break;
+       }
+
+       ntlmssp_want_feature(ntlmssp_state, features);
+
        blob_in = data_blob_null;
 
        do {
@@ -130,7 +242,16 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
        /* we have a reference conter on ntlmssp_state, if we are signing
           then the state will be kept by the signing engine */
 
-       ntlmssp_end(&ntlmssp_state);
+       if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+               ads->ldap.out.min = 4;
+               ads->ldap.out.max = 0x0FFFFFFF - NTLMSSP_SIG_SIZE;
+               ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
+               ads->ldap.in.min = 4;
+               ads->ldap.in.max = 0x0FFFFFFF;
+               ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
+       } else {
+               ntlmssp_end(&ntlmssp_state);
+       }
 
        return ADS_ERROR(rc);
 }