r25598: Add missing become_root/unbecome_root around calls of add_aliases.
[samba.git] / source / libsmb / smb_seal.c
index ed2c66013e8d29c5cd782e05068de2ac67e71f40..33352b85ceb14b35c5ae3c61006acdc734a2b528 100644 (file)
@@ -5,7 +5,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,
@@ -14,8 +14,7 @@
    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"
@@ -30,13 +29,15 @@ NTSTATUS get_enc_ctx_num(char *buf, uint16 *p_enc_ctx_num)
                return NT_STATUS_INVALID_BUFFER_SIZE;
        }
 
-       if (buf[4] == (char)0xFF && buf[5] == 'S') {
-               if (buf [6] == 'M' && buf[7] == 'B') {
+       if (buf[4] == (char)0xFF) {
+               if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
                        /* Not an encrypted buffer. */
                        return NT_STATUS_NOT_FOUND;
                }
-               *p_enc_ctx_num = SVAL(buf,6);
-               return NT_STATUS_OK;
+               if (buf[5] == 'E') {
+                       *p_enc_ctx_num = SVAL(buf,6);
+                       return NT_STATUS_OK;
+               }
        }
        return NT_STATUS_INVALID_NETWORK_RESPONSE;
 }
@@ -54,44 +55,56 @@ BOOL common_encryption_on(struct smb_trans_enc_state *es)
 /******************************************************************************
  Generic code for client and server.
  NTLM decrypt an incoming buffer.
+ Abartlett tells me that SSPI puts the signature first before the encrypted
+ output, so cope with the same for compatibility.
 ******************************************************************************/
 
 NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
 {
        NTSTATUS status;
        size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+       size_t data_len;
+       char *inbuf;
        DATA_BLOB sig;
 
        if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
+       inbuf = (char *)smb_xmemdup(buf, buf_len);
+
        /* Adjust for the signature. */
-       buf_len -= NTLMSSP_SIG_SIZE;
+       data_len = buf_len - 8 - NTLMSSP_SIG_SIZE;
 
-       /* Save off the signature. */
-       sig = data_blob(buf+buf_len, NTLMSSP_SIG_SIZE);
+       /* Point at the signature. */
+       sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE);
 
        status = ntlmssp_unseal_packet(ntlmssp_state,
-               (unsigned char *)buf + 8, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
-               buf_len - 8,
-               (unsigned char *)buf + 8,
-               buf_len - 8,
+               (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'E' <enc> <ctx> */
+               data_len,
+               (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE,
+               data_len,
                &sig);
 
        if (!NT_STATUS_IS_OK(status)) {
-               data_blob_free(&sig);
+               SAFE_FREE(inbuf);
                return status;
        }
 
+       memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
+
        /* Reset the length. */
-       smb_setlen(buf, smb_len(buf) - NTLMSSP_SIG_SIZE);
+       smb_setlen(inbuf, buf, data_len + 4);
+
+       SAFE_FREE(inbuf);
        return NT_STATUS_OK;
 }
 
 /******************************************************************************
  Generic code for client and server.
  NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
+ Abartlett tells me that SSPI puts the signature first before the encrypted
+ output, so do the same for compatibility.
 ******************************************************************************/
 
 NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
@@ -101,12 +114,12 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
 {
        NTSTATUS status;
        char *buf_out;
-       size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+       size_t data_len = smb_len(buf) - 4; /* Ignore the 0xFF SMB bytes. */
        DATA_BLOB sig;
 
        *ppbuf_out = NULL;
 
-       if (buf_len < 8) {
+       if (data_len == 0) {
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
@@ -115,21 +128,21 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
         * check needed.
         */
 
-       /* Copy the original buffer. */
+       buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len);
+
+       /* Copy the data from the original buffer. */
 
-       buf_out = SMB_XMALLOC_ARRAY(char, buf_len + NTLMSSP_SIG_SIZE);
-       memcpy(buf_out, buf, buf_len);
-       /* Last 16 bytes undefined here... */
+       memcpy(buf_out + 8 + NTLMSSP_SIG_SIZE, buf + 8, data_len);
 
        smb_set_enclen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num);
 
        sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
 
        status = ntlmssp_seal_packet(ntlmssp_state,
-               (unsigned char *)buf_out + 8, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
-               buf_len - 8,
-               (unsigned char *)buf_out + 8,
-               buf_len - 8,
+               (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
+               data_len,
+               (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE,
+               data_len,
                &sig);
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -138,7 +151,8 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
                return status;
        }
 
-       memcpy(buf_out+buf_len, sig.data, NTLMSSP_SIG_SIZE);
+       /* First 16 data bytes are signature for SSPI compatibility. */
+       memcpy(buf_out + 8, sig.data, NTLMSSP_SIG_SIZE);
        *ppbuf_out = buf_out;
        return NT_STATUS_OK;
 }
@@ -150,7 +164,7 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
 ******************************************************************************/
 
 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
-NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
+static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
 {
        gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
        OM_uint32 ret = 0;
@@ -177,8 +191,7 @@ NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, cha
                ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
                DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
                        ads_errstr(adss) ));
-               /* Um - no mapping for gss-errs to NTSTATUS yet. */
-               return ads_ntstatus(adss);
+               return map_nt_error_from_gss(ret, minor);
        }
 
        if (out_buf.length > in_buf.length) {
@@ -190,20 +203,18 @@ NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, cha
        }
 
        memcpy(buf + 8, out_buf.value, out_buf.length);
-       smb_setlen(buf, out_buf.length + 4);
+       smb_setlen((char *)out_buf.value, buf, out_buf.length + 4);
 
        gss_release_buffer(&minor, &out_buf);
        return NT_STATUS_OK;
 }
-#endif
 
 /******************************************************************************
  Generic code for client and server.
  gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
 ******************************************************************************/
 
-#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
-NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
+static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
                                        uint16 enc_ctx_num,
                                        char *buf,
                                        char **ppbuf_out)
@@ -236,8 +247,7 @@ NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
                ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
                DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
                        ads_errstr(adss) ));
-               /* Um - no mapping for gss-errs to NTSTATUS yet. */
-               return ads_ntstatus(adss);
+               return map_nt_error_from_gss(ret, minor);
        }
 
        if (!flags_got) {
@@ -258,7 +268,7 @@ NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
         * bother :-*(. JRA.
         */
 
-       *ppbuf_out = SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
+       *ppbuf_out = (char *)SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
        if (!*ppbuf_out) {
                gss_release_buffer(&minor, &out_buf);
                return NT_STATUS_NO_MEMORY;
@@ -332,8 +342,12 @@ static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
        OM_uint32 minor = 0;
        struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
 
-       gss_release_cred(&minor, &gss_state->creds);
-       gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
+       if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
+               gss_release_cred(&minor, &gss_state->creds);
+       }
+       if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
+               gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
+       }
        SAFE_FREE(*pp_gss_state);
 }
 #endif