Spelling fixes for lib/compression.
[sfrench/samba-autobuild/.git] / source3 / smbd / negprot.c
index 61be2e8f9a021b90d55e6672713a82d12d38fd8d..81d29d90f97f5a106770dec0b84cd752845beccb 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    negprot reply code
    Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Volker Lendecke 2007
    
    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
 */
 
 #include "includes.h"
+#include "smbd/globals.h"
+#include "../libcli/auth/spnego.h"
 
 extern fstring remote_proto;
-extern enum protocol_types Protocol;
-extern int max_recv;
-
-BOOL global_encrypted_passwords_negotiated = False;
-BOOL global_spnego_negotiated = False;
-struct auth_context *negprot_global_auth_context = NULL;
 
 static void get_challenge(uint8 buff[8])
 {
        NTSTATUS nt_status;
-       const uint8 *cryptkey;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
        /* We might be called more than once, multiple negprots are
         * permitted */
-       if (negprot_global_auth_context) {
-               DEBUG(3, ("get challenge: is this a secondary negprot?  negprot_global_auth_context is non-NULL!\n"));
-               (negprot_global_auth_context->free)(&negprot_global_auth_context);
+       if (sconn->smb1.negprot.auth_context) {
+               DEBUG(3, ("get challenge: is this a secondary negprot? "
+                         "sconn->negprot.auth_context is non-NULL!\n"));
+                       sconn->smb1.negprot.auth_context->free(
+                               &sconn->smb1.negprot.auth_context);
        }
 
        DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
-       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
-               DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
+       nt_status = make_auth_context_subsystem(
+               &sconn->smb1.negprot.auth_context);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("make_auth_context_subsystem returned %s",
+                         nt_errstr(nt_status)));
                smb_panic("cannot make_negprot_global_auth_context!");
        }
        DEBUG(10, ("get challenge: getting challenge\n"));
-       cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
-       memcpy(buff, cryptkey, 8);
+       sconn->smb1.negprot.auth_context->get_ntlm_challenge(
+               sconn->smb1.negprot.auth_context, buff);
 }
 
 /****************************************************************************
@@ -58,7 +60,7 @@ static void reply_corep(struct smb_request *req, uint16 choice)
        reply_outbuf(req, 1, 0);
        SSVAL(req->outbuf, smb_vwv0, choice);
 
-       Protocol = PROTOCOL_CORE;
+       set_Protocol(PROTOCOL_CORE);
 }
 
 /****************************************************************************
@@ -78,7 +80,7 @@ static void reply_coreplus(struct smb_request *req, uint16 choice)
        SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
        SSVAL(req->outbuf,smb_vwv1,0x1); /* user level security, don't
                                          * encrypt */
-       Protocol = PROTOCOL_COREPLUS;
+       set_Protocol(PROTOCOL_COREPLUS);
 }
 
 /****************************************************************************
@@ -90,29 +92,32 @@ static void reply_lanman1(struct smb_request *req, uint16 choice)
        int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
        int secword=0;
        time_t t = time(NULL);
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+       sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();
 
-       if (lp_security()>=SEC_USER)
+       if (lp_security()>=SEC_USER) {
                secword |= NEGOTIATE_SECURITY_USER_LEVEL;
-       if (global_encrypted_passwords_negotiated)
+       }
+       if (sconn->smb1.negprot.encrypted_passwords) {
                secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
+       }
 
-       reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0);
+       reply_outbuf(req, 13, sconn->smb1.negprot.encrypted_passwords?8:0);
 
        SSVAL(req->outbuf,smb_vwv0,choice);
        SSVAL(req->outbuf,smb_vwv1,secword);
        /* Create a token value and add it to the outgoing packet. */
-       if (global_encrypted_passwords_negotiated) {
+       if (sconn->smb1.negprot.encrypted_passwords) {
                get_challenge((uint8 *)smb_buf(req->outbuf));
                SSVAL(req->outbuf,smb_vwv11, 8);
        }
 
-       Protocol = PROTOCOL_LANMAN1;
+       set_Protocol(PROTOCOL_LANMAN1);
 
        /* Reply, SMBlockread, SMBwritelock supported. */
        SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
-       SSVAL(req->outbuf,smb_vwv2,max_recv);
+       SSVAL(req->outbuf,smb_vwv2,sconn->smb1.negprot.max_recv);
        SSVAL(req->outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
        SSVAL(req->outbuf,smb_vwv4,1);
        SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support
@@ -134,31 +139,34 @@ static void reply_lanman2(struct smb_request *req, uint16 choice)
        int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
        int secword=0;
        time_t t = time(NULL);
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+       sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();
   
-       if (lp_security()>=SEC_USER)
+       if (lp_security()>=SEC_USER) {
                secword |= NEGOTIATE_SECURITY_USER_LEVEL;
-       if (global_encrypted_passwords_negotiated)
+       }
+       if (sconn->smb1.negprot.encrypted_passwords) {
                secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
+       }
 
-       reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0);
+       reply_outbuf(req, 13, sconn->smb1.negprot.encrypted_passwords?8:0);
 
        SSVAL(req->outbuf,smb_vwv0,choice);
        SSVAL(req->outbuf,smb_vwv1,secword);
        SIVAL(req->outbuf,smb_vwv6,sys_getpid());
 
        /* Create a token value and add it to the outgoing packet. */
-       if (global_encrypted_passwords_negotiated) {
+       if (sconn->smb1.negprot.encrypted_passwords) {
                get_challenge((uint8 *)smb_buf(req->outbuf));
                SSVAL(req->outbuf,smb_vwv11, 8);
        }
 
-       Protocol = PROTOCOL_LANMAN2;
+       set_Protocol(PROTOCOL_LANMAN2);
 
        /* Reply, SMBlockread, SMBwritelock supported. */
        SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
-       SSVAL(req->outbuf,smb_vwv2,max_recv);
+       SSVAL(req->outbuf,smb_vwv2,sconn->smb1.negprot.max_recv);
        SSVAL(req->outbuf,smb_vwv3,lp_maxmux());
        SSVAL(req->outbuf,smb_vwv4,1);
        SSVAL(req->outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
@@ -170,7 +178,7 @@ static void reply_lanman2(struct smb_request *req, uint16 choice)
  Generate the spnego negprot reply blob. Return the number of bytes used.
 ****************************************************************************/
 
-static DATA_BLOB negprot_spnego(void)
+DATA_BLOB negprot_spnego(void)
 {
        DATA_BLOB blob;
        nstring dos_name;
@@ -184,8 +192,9 @@ static DATA_BLOB negprot_spnego(void)
                                   OID_NTLMSSP,
                                   NULL};
        const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       global_spnego_negotiated = True;
+       sconn->smb1.negprot.spnego = true;
 
        memset(guid, '\0', sizeof(guid));
 
@@ -215,7 +224,7 @@ static DATA_BLOB negprot_spnego(void)
 
        */
 
-       if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
+       if (lp_security() != SEC_ADS && !USE_KERBEROS_KEYTAB) {
 #if 0
                /* Code for PocketPC client */
                blob = data_blob(guid, 16);
@@ -228,10 +237,9 @@ static DATA_BLOB negprot_spnego(void)
                char *host_princ_s = NULL;
                name_to_fqdn(myname, global_myname());
                strlower_m(myname);
-               asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm());
-               if (host_princ_s == NULL) {
-                       blob = data_blob_null;
-                       return blob;
+               if (asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm())
+                   == -1) {
+                       return data_blob_null;
                }
                blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);
                SAFE_FREE(host_princ_s);
@@ -252,11 +260,12 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
 
        int secword=0;
        char *p, *q;
-       BOOL negotiate_spnego = False;
+       bool negotiate_spnego = False;
        time_t t = time(NULL);
        ssize_t ret;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+       sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();
 
        /* Check the flags field to see if this is Vista.
           WinXP sets it and Vista does not. But we have to 
@@ -275,7 +284,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
        /* do spnego in user level security if the client
           supports it and we can do encrypted passwords */
        
-       if (global_encrypted_passwords_negotiated && 
+       if (sconn->smb1.negprot.encrypted_passwords &&
            (lp_security() != SEC_SHARE) &&
            lp_use_spnego() &&
            (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
@@ -309,11 +318,13 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
        if (lp_host_msdfs())
                capabilities |= CAP_DFS;
        
-       if (lp_security() >= SEC_USER)
+       if (lp_security() >= SEC_USER) {
                secword |= NEGOTIATE_SECURITY_USER_LEVEL;
-       if (global_encrypted_passwords_negotiated)
+       }
+       if (sconn->smb1.negprot.encrypted_passwords) {
                secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
-       
+       }
+
        if (lp_server_signing()) {
                if (lp_security() >= SEC_USER) {
                        secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
@@ -321,7 +332,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
                        capabilities &= ~CAP_RAW_MODE;
                        if (lp_server_signing() == Required)
                                secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
-                       srv_set_signing_negotiated();
+                       srv_set_signing_negotiated(smbd_server_conn);
                } else {
                        DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
                        if (lp_server_signing() == Required) {
@@ -333,11 +344,12 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
        SSVAL(req->outbuf,smb_vwv0,choice);
        SCVAL(req->outbuf,smb_vwv1,secword);
        
-       Protocol = PROTOCOL_NT1;
+       set_Protocol(PROTOCOL_NT1);
        
        SSVAL(req->outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
        SSVAL(req->outbuf,smb_vwv2+1,1); /* num vcs */
-       SIVAL(req->outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
+       SIVAL(req->outbuf,smb_vwv3+1,
+             sconn->smb1.negprot.max_recv); /* max buffer. LOTS! */
        SIVAL(req->outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
        SIVAL(req->outbuf,smb_vwv7+1,sys_getpid()); /* session key */
        SIVAL(req->outbuf,smb_vwv9+1,capabilities); /* capabilities */
@@ -347,7 +359,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice)
        p = q = smb_buf(req->outbuf);
        if (!negotiate_spnego) {
                /* Create a token value and add it to the outgoing packet. */
-               if (global_encrypted_passwords_negotiated) {
+               if (sconn->smb1.negprot.encrypted_passwords) {
                        uint8 chal[8];
                        /* note that we do not send a challenge at all if
                           we are using plaintext */
@@ -486,6 +498,7 @@ static const struct {
        void (*proto_reply_fn)(struct smb_request *req, uint16 choice);
        int protocol_level;
 } supported_protocols[] = {
+       {"SMB 2.002",               "SMB2",     reply_smb2002,  PROTOCOL_SMB2},
        {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
        {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
        {"POSIX 2",                 "NT1",      reply_nt1,      PROTOCOL_NT1},
@@ -505,43 +518,50 @@ static const struct {
  conn POINTER CAN BE NULL HERE !
 ****************************************************************************/
 
-void reply_negprot(connection_struct *conn, struct smb_request *req)
+void reply_negprot(struct smb_request *req)
 {
-       size_t size = smb_len(req->inbuf) + 4;
        int choice= -1;
        int protocol;
-       char *p;
+       const char *p;
        int arch = ARCH_ALL;
        int num_cliprotos;
        char **cliprotos;
        int i;
-
-       static BOOL done_negprot = False;
+       size_t converted_size;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
        START_PROFILE(SMBnegprot);
 
-       if (done_negprot) {
+       if (sconn->smb1.negprot.done) {
                END_PROFILE(SMBnegprot);
                exit_server_cleanly("multiple negprot's are not permitted");
        }
-       done_negprot = True;
+       sconn->smb1.negprot.done = true;
+
+       if (req->buflen == 0) {
+               DEBUG(0, ("negprot got no protocols\n"));
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBnegprot);
+               return;
+       }
 
-       if (req->inbuf[size-1] != '\0') {
+       if (req->buf[req->buflen-1] != '\0') {
                DEBUG(0, ("negprot protocols not 0-terminated\n"));
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                END_PROFILE(SMBnegprot);
                return;
        }
 
-       p = smb_buf(req->inbuf)+1;
+       p = (const char *)req->buf + 1;
 
        num_cliprotos = 0;
        cliprotos = NULL;
 
-       while (smb_bufrem(req->inbuf, p) > 0) {
+       while (smbreq_bufrem(req, p) > 0) {
+
                char **tmp;
 
-               tmp = TALLOC_REALLOC_ARRAY(tmp_talloc_ctx(), cliprotos, char *,
+               tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), cliprotos, char *,
                                           num_cliprotos+1);
                if (tmp == NULL) {
                        DEBUG(0, ("talloc failed\n"));
@@ -553,8 +573,8 @@ void reply_negprot(connection_struct *conn, struct smb_request *req)
 
                cliprotos = tmp;
 
-               if (pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p)
-                   == (size_t)-1) {
+               if (!pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p,
+                                      &converted_size)) {
                        DEBUG(0, ("pull_ascii_talloc failed\n"));
                        TALLOC_FREE(cliprotos);
                        reply_nterror(req, NT_STATUS_NO_MEMORY);
@@ -671,11 +691,13 @@ void reply_negprot(connection_struct *conn, struct smb_request *req)
                DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
        } else {
                DEBUG(0,("No protocol supported !\n"));
+               reply_outbuf(req, 1, 0);
+               SSVAL(req->outbuf, smb_vwv0, choice);
        }
   
        DEBUG( 5, ( "negprot index=%d\n", choice ) );
 
-       if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) {
+       if ((lp_server_signing() == Required) && (get_Protocol() < PROTOCOL_NT1)) {
                exit_server_cleanly("SMB signing is required and "
                        "client negotiated a downlevel protocol");
        }