Add SMB encryption. Still fixing client decrypt but
authorJeremy Allison <jra@samba.org>
Thu, 27 Dec 2007 01:12:36 +0000 (17:12 -0800)
committerJeremy Allison <jra@samba.org>
Thu, 27 Dec 2007 01:12:36 +0000 (17:12 -0800)
negotiation works.
Jeremy.
(This used to be commit d78045601af787731f0737b8627450018902b104)

34 files changed:
source3/Makefile.in
source3/client/client.c
source3/include/client.h
source3/include/smb.h
source3/include/smb_macros.h
source3/include/trans2.h
source3/lib/dummysmbd.c
source3/lib/util.c
source3/lib/util_sock.c
source3/libads/ads_status.c
source3/libsmb/cliconnect.c
source3/libsmb/clidgram.c
source3/libsmb/clientgen.c
source3/libsmb/clifile.c
source3/libsmb/clifsinfo.c
source3/libsmb/clilist.c
source3/libsmb/climessage.c
source3/libsmb/clioplock.c
source3/libsmb/cliprint.c
source3/libsmb/clireadwrite.c
source3/libsmb/clitrans.c
source3/libsmb/errormap.c
source3/libsmb/smb_seal.c [new file with mode: 0644]
source3/nmbd/nmbd_packets.c
source3/param/loadparm.c
source3/smbd/aio.c
source3/smbd/error.c
source3/smbd/notify.c
source3/smbd/oplock.c
source3/smbd/pipes.c
source3/smbd/process.c
source3/smbd/reply.c
source3/smbd/seal.c [new file with mode: 0644]
source3/smbd/trans2.c

index 10a14d0a551b363833dd769714384da2c1c97969..9d8ad3e68b5cf5ea1e3d38dbd419cc870fe0ea1e 100644 (file)
@@ -374,7 +374,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
             libsmb/clistr.o libsmb/cliquota.o libsmb/clifsinfo.o libsmb/clidfs.o \
              libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
             libsmb/clioplock.o $(ERRORMAP_OBJ) libsmb/clirap2.o \
-            $(DOSERR_OBJ) \
+            libsmb/smb_seal.o $(DOSERR_OBJ) \
             $(RPC_PARSE_OBJ1) $(LIBSAMBA_OBJ) $(LIBNMB_OBJ)
 
 RPC_CLIENT_OBJ1 = rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o
@@ -551,7 +551,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
                smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \
               smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \
               smbd/blocking.o smbd/sec_ctx.o smbd/srvstr.o \
-              smbd/vfs.o smbd/statcache.o \
+              smbd/vfs.o smbd/statcache.o smbd/seal.o \
                smbd/posix_acls.o lib/sysacls.o $(SERVER_MUTEX_OBJ) \
               smbd/process.o smbd/service.o smbd/error.o \
               printing/printfsp.o lib/sysquotas.o lib/sysquotas_linux.o \
index f761d92baccd72655fd279dcb5f2202b3a032ef6..665a051190cba35abe7ee7fb83cc1d4978a8c997 100644 (file)
@@ -2178,6 +2178,48 @@ static int cmd_open(void)
        return 0;
 }
 
+static int cmd_posix_encrypt(void)
+{
+       TALLOC_CTX *ctx = talloc_tos();
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+       if (cli->use_kerberos) {
+               status = cli_gss_smb_encryption_start(cli);
+       } else {
+               char *domain = NULL;
+               char *user = NULL;
+               char *password = NULL;
+
+               if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
+                       d_printf("posix_encrypt domain user password\n");
+                       return 1;
+               }
+
+               if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
+                       d_printf("posix_encrypt domain user password\n");
+                       return 1;
+               }
+
+               if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
+                       d_printf("posix_encrypt domain user password\n");
+                       return 1;
+               }
+
+               status = cli_raw_ntlm_smb_encryption_start(cli,
+                                                       user,
+                                                       password,
+                                                       domain);
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
+       } else {
+               d_printf("encryption on\n");
+       }
+
+       return 0;
+}
+
 /****************************************************************************
 ****************************************************************************/
 
@@ -3803,6 +3845,7 @@ static struct {
   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
   {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
+  {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
   {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
index 0047b2bf235bdecdda8df233fb4b79ae5932c1f4..f8adf567de904e5edc65db31d4064d837b8d1504 100644 (file)
@@ -27,7 +27,9 @@
    will be a multiple of the page size on almost any system */
 #define CLI_BUFFER_SIZE (0xFFFF)
 #define CLI_SAMBA_MAX_LARGE_READX_SIZE (127*1024) /* Works for Samba servers */
+#define CLI_SAMBA_MAX_LARGE_WRITEX_SIZE (127*1024) /* Works for Samba servers */
 #define CLI_WINDOWS_MAX_LARGE_READX_SIZE ((64*1024)-2) /* Windows servers are broken.... */
+#define CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE ((64*1024)-2) /* Windows servers are broken.... */
 #define CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE (0xFFFF00) /* 24-bit len. */
 #define CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE (0xFFFF00) /* 24-bit len. */
 
@@ -79,6 +81,28 @@ struct rpc_pipe_client {
        struct dcinfo *dc;
 };
 
+/* Transport encryption state. */
+enum smb_trans_enc_type { SMB_TRANS_ENC_NTLM, SMB_TRANS_ENC_GSS };
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+struct smb_tran_enc_state_gss {
+        gss_ctx_id_t gss_ctx;
+        gss_cred_id_t creds;
+};
+#endif
+
+struct smb_trans_enc_state {
+        enum smb_trans_enc_type smb_enc_type;
+        uint16 enc_ctx_num;
+        bool enc_on;
+        union {
+                NTLMSSP_STATE *ntlmssp_state;
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+                struct smb_tran_enc_state_gss *gss_state;
+#endif
+        } s;
+};
+
 struct cli_state {
        int port;
        int fd;
@@ -142,6 +166,8 @@ struct cli_state {
 
        smb_sign_info sign_info;
 
+       struct smb_trans_enc_state *trans_enc_state; /* Setup if we're encrypting SMB's. */
+
        /* the session key for this CLI, outside
           any per-pipe authenticaion */
        DATA_BLOB user_session_key;
index 63ae51ecd4fcdbe25bf3cb325e90b3cd7b2bb69f..2ffd530fb06e85a9d02c16b09159346022b7f09c 100644 (file)
@@ -80,7 +80,8 @@ enum smb_read_errors {
        SMB_WRITE_ERROR, /* This error code can go into the client smb_rw_error. */
        SMB_READ_BAD_SIG,
        SMB_NO_MEMORY,
-       SMB_DO_NOT_DO_TDIS /* cli_close_connection() check for this when smbfs wants to keep tree connected */
+       SMB_DO_NOT_DO_TDIS, /* cli_close_connection() check for this when smbfs wants to keep tree connected */
+       SMB_READ_BAD_DECRYPT
 };
 
 #define DIR_STRUCT_SIZE 43
index 0dfb5969948c63d1b861247b06731eee64a757e0..9bacdce1db7d8ea817d52c997caa809823c7007a 100644 (file)
 #define SMB_LARGE_LKLEN_OFFSET_HIGH(indx) (12 + (20 * (indx)))
 #define SMB_LARGE_LKLEN_OFFSET_LOW(indx) (16 + (20 * (indx)))
 
-#define ERROR_DOS(class,code) error_packet(outbuf,class,code,NT_STATUS_OK,__LINE__,__FILE__)
-#define ERROR_NT(status) error_packet(outbuf,0,0,status,__LINE__,__FILE__)
-#define ERROR_OPEN(status) error_open(outbuf,status,__LINE__,__FILE__)
-#define ERROR_FORCE_NT(status) error_packet(outbuf,-1,-1,status,__LINE__,__FILE__)
-#define ERROR_BOTH(status,class,code) error_packet(outbuf,class,code,status,__LINE__,__FILE__)
+#define ERROR_DOS(class,code) error_packet(inbuf,outbuf,class,code,NT_STATUS_OK,__LINE__,__FILE__)
+#define ERROR_NT(status) error_packet(inbuf,outbuf,0,0,status,__LINE__,__FILE__)
+#define ERROR_FORCE_NT(status) error_packet(inbuf,outbuf,-1,-1,status,__LINE__,__FILE__)
+#define ERROR_BOTH(status,class,code) error_packet(inbuf,outbuf,class,code,status,__LINE__,__FILE__)
 
 #define reply_nterror(req,status) reply_nt_error(req,status,__LINE__,__FILE__)
 #define reply_force_nterror(req,status) reply_force_nt_error(req,status,__LINE__,__FILE__)
 #define reply_botherror(req,status,eclass,ecode) reply_both_error(req,eclass,ecode,status,__LINE__,__FILE__)
 #define reply_unixerror(req,defclass,deferror) reply_unix_error(req,defclass,deferror,NT_STATUS_OK,__LINE__,__FILE__)
 
-/* this is how errors are generated */
-#define UNIXERROR(defclass,deferror) unix_error_packet(outbuf,defclass,deferror,NT_STATUS_OK,__LINE__,__FILE__)
-
 /* these are the datagram types */
 #define DGRAM_DIRECT_UNIQUE 0x10
 
 #define smb_offset(p,buf) (PTR_DIFF(p,buf+4) + chain_size)
 
 #define smb_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|((PVAL(buf,1)&1)<<16))
-#define _smb_setlen(buf,len) do { buf[0] = 0; buf[1] = (len&0x10000)>>16; \
-        buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF; } while (0)
+#define _smb_setlen(buf,len) do { buf[0] = 0; buf[1] = ((len)&0x10000)>>16; \
+        buf[2] = ((len)&0xFF00)>>8; buf[3] = (len)&0xFF; } while (0)
 
 #define smb_len_large(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
 #define _smb_setlen_large(buf,len) do { buf[0] = 0; buf[1] = ((len)&0xFF0000)>>16; \
index f7f3ef21497579cbfc9063c978a7e1bb17c5d09f..8ed075d418193cf5d2261acc7d8ebf17fc46278c 100644 (file)
@@ -566,7 +566,6 @@ findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
         __u8 * psid_list  may be empty
 */
 
-
 /* ... more as we think of them :-). */
 
 /* SMB POSIX ACL definitions. */
@@ -653,6 +652,29 @@ enum smb_whoami_flags {
        DOM_SID[] -             list of SIDs (may be empty)
 */
 
+/*
+ * The following trans2 is done between client and server
+ * as a FSINFO call to set up the encryption state for transport
+ * encryption.
+ * This is a subcommand of the TRANS2_QFSINFO.
+ *
+ * The request looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI request.
+ *
+ * The reply looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI reply - if error
+ *                 is NT_STATUS_OK then we're done, if it's
+ *                 NT_STATUS_MORE_PROCESSING_REQUIRED then the
+ *                 client needs to keep going. If it's an
+ *                 error it can be any NT_STATUS error.
+ *
+ */
+
+#define SMB_REQUEST_TRANSPORT_ENCRYPTION     0x203 /* QFSINFO */
+
+
 /* The query/set info levels for POSIX ACLs. */
 #define SMB_QUERY_POSIX_ACL  0x204
 #define SMB_SET_POSIX_ACL  0x204
index e3b179b7634efda38818eb5a72f01428d54a55f8..464ba9230636b55c06669cebd67dfb7e64b13248 100644 (file)
@@ -52,3 +52,23 @@ NTSTATUS can_delete_directory(struct connection_struct *conn,
        return NT_STATUS_OK;
 }
 
+NTSTATUS srv_decrypt_buffer(char *buf)
+{
+        return NT_STATUS_OK;
+}
+
+NTSTATUS srv_encrypt_buffer(char *buffer, char **buf_out)
+{
+        *buf_out = buffer;
+        return NT_STATUS_OK;
+}
+
+void srv_free_enc_buffer(char *buf)
+{
+        ;
+}
+
+bool srv_encryption_on(void)
+{
+        return false;
+}
index 11c14ea5389674985cde410495853ef671f1d722..7f8a297facac6979cf17a947330e914f73f4d518 100644 (file)
@@ -605,32 +605,30 @@ void show_msg(char *buf)
 }
 
 /*******************************************************************
- Set the length and marker of an smb packet.
+ Set the length and marker of an encrypted smb packet.
 ********************************************************************/
 
-void smb_setlen(char *buf,int len)
+void smb_set_enclen(char *buf,int len,uint16 enc_ctx_num)
 {
        _smb_setlen(buf,len);
 
        SCVAL(buf,4,0xFF);
-       SCVAL(buf,5,'S');
-       SCVAL(buf,6,'M');
-       SCVAL(buf,7,'B');
+       SCVAL(buf,5,'E');
+       SSVAL(buf,6,enc_ctx_num);
 }
 
 /*******************************************************************
- Setup the word count and byte count for a smb message.
+ Set the length and marker of an smb packet.
 ********************************************************************/
 
-int set_message(char *buf,int num_words,int num_bytes,bool zero)
+void smb_setlen(char *buf,int len)
 {
-       if (zero && (num_words || num_bytes)) {
-               memset(buf + smb_size,'\0',num_words*2 + num_bytes);
-       }
-       SCVAL(buf,smb_wct,num_words);
-       SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);  
-       smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
-       return (smb_size + num_words*2 + num_bytes);
+       _smb_setlen(buf,len);
+
+       SCVAL(buf,4,0xFF);
+       SCVAL(buf,5,'S');
+       SCVAL(buf,6,'M');
+       SCVAL(buf,7,'B');
 }
 
 /*******************************************************************
@@ -641,20 +639,10 @@ int set_message_bcc(char *buf,int num_bytes)
 {
        int num_words = CVAL(buf,smb_wct);
        SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
-       smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+       _smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
        return (smb_size + num_words*2 + num_bytes);
 }
 
-/*******************************************************************
- Setup only the byte count for a smb message, using the end of the
- message as a marker.
-********************************************************************/
-
-int set_message_end(void *outbuf,void *end_ptr)
-{
-       return set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf)));
-}
-
 /*******************************************************************
  Add a data blob to the end of a smb_buf, adjusting bcc and smb_len.
  Return the bytes added
index 8f1bd9e686e4056e44754acd0303e2b1c45c9a3c..d16a8f079a0c3d95c3017da0175646f6afb637f7 100644 (file)
@@ -1287,6 +1287,17 @@ bool receive_smb(int fd, char *buffer, unsigned int timeout, enum smb_read_error
                return false;
        }
 
+       if (srv_encryption_on()) {
+               NTSTATUS status = srv_decrypt_buffer(buffer);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("receive_smb: SMB decryption failed "
+                               "on incoming packet! Error %s\n",
+                               nt_errstr(status) ));
+                       cond_set_smb_read_error(pre, SMB_READ_BAD_DECRYPT);
+                       return false;
+               }
+       }
+
        /* Check the incoming SMB signature. */
        if (!srv_check_sign_mac(buffer, true)) {
                DEBUG(0, ("receive_smb: SMB Signature verification "
@@ -1307,22 +1318,35 @@ bool send_smb(int fd, char *buffer)
        size_t len;
        size_t nwritten=0;
        ssize_t ret;
+       char *buf_out = buffer;
 
        /* Sign the outgoing packet if required. */
-       srv_calculate_sign_mac(buffer);
+       srv_calculate_sign_mac(buf_out);
+
+       if (srv_encryption_on()) {
+               NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("send_smb: SMB encryption failed "
+                               "on outgoing packet! Error %s\n",
+                               nt_errstr(status) ));
+                       return false;
+               }
+       }
 
-       len = smb_len(buffer) + 4;
+       len = smb_len(buf_out) + 4;
 
        while (nwritten < len) {
-               ret = write_data(fd,buffer+nwritten,len - nwritten);
+               ret = write_data(fd,buf_out+nwritten,len - nwritten);
                if (ret <= 0) {
                        DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
                                (int)len,(int)ret, strerror(errno) ));
+                       srv_free_enc_buffer(buf_out);
                        return false;
                }
                nwritten += ret;
        }
 
+       srv_free_enc_buffer(buf_out);
        return true;
 }
 
index ecef9d224b3ecb11e5ae0112c514b49fe618f5a1..29148e85439d0f264d3874d9c3ddc30a53b998c9 100644 (file)
@@ -141,3 +141,12 @@ const char *ads_errstr(ADS_STATUS status)
        }
 }
 
+#ifdef HAVE_GSSAPI
+NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min)
+{
+        ADS_STATUS adss = ADS_ERROR_GSS(maj, min);
+        DEBUG(10,("gss_err_to_ntstatus: Error %s\n",
+                ads_errstr(adss) ));
+        return ads_ntstatus(adss);
+}
+#endif
index 33110c803f7e83e392e083e3c068c39b99f8a2bb..4560521d4a2b72bc845a7a28d93e62f9c505037c 100644 (file)
@@ -98,7 +98,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
 
        /* send a session setup command */
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,10, 0, True);
+       cli_set_message(cli->outbuf,10, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
        
@@ -168,7 +168,7 @@ static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
        uint32 capabilities = cli_session_setup_capabilities(cli);
 
        memset(cli->outbuf, '\0', smb_size);
-       set_message(cli->outbuf,13,0,True);
+       cli_set_message(cli->outbuf,13,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
                        
@@ -228,7 +228,7 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
        fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
 
        memset(cli->outbuf, '\0', smb_size);
-       set_message(cli->outbuf,13,0,True);
+       cli_set_message(cli->outbuf,13,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
                        
@@ -377,7 +377,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
        /* send a session setup command */
        memset(cli->outbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,13,0,True);
+       cli_set_message(cli->outbuf,13,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
                        
@@ -457,7 +457,7 @@ static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
        /* send a session setup command */
        memset(cli->outbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,12,0,True);
+       cli_set_message(cli->outbuf,12,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
 
        cli_setup_packet(cli);
@@ -1028,7 +1028,7 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
 bool cli_ulogoff(struct cli_state *cli)
 {
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,2,0,True);
+       cli_set_message(cli->outbuf,2,0,True);
        SCVAL(cli->outbuf,smb_com,SMBulogoffX);
        cli_setup_packet(cli);
        SSVAL(cli->outbuf,smb_vwv0,0xFF);
@@ -1106,7 +1106,7 @@ bool cli_send_tconX(struct cli_state *cli,
        slprintf(fullshare, sizeof(fullshare)-1,
                 "\\\\%s\\%s", cli->desthost, share);
 
-       set_message(cli->outbuf,4, 0, True);
+       cli_set_message(cli->outbuf,4, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBtconX);
        cli_setup_packet(cli);
 
@@ -1157,7 +1157,7 @@ bool cli_send_tconX(struct cli_state *cli,
 bool cli_tdis(struct cli_state *cli)
 {
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
        SCVAL(cli->outbuf,smb_com,SMBtdis);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -1189,7 +1189,7 @@ void cli_negprot_send(struct cli_state *cli)
        memset(cli->outbuf,'\0',smb_size);
 
        /* setup the protocol strings */
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
 
        p = smb_buf(cli->outbuf);
        for (numprots=0;
@@ -1229,7 +1229,7 @@ bool cli_negprot(struct cli_state *cli)
             numprots++)
                plength += strlen(prots[numprots].name)+2;
     
-       set_message(cli->outbuf,0,plength,True);
+       cli_set_message(cli->outbuf,0,plength,True);
 
        p = smb_buf(cli->outbuf);
        for (numprots=0;
@@ -1806,7 +1806,7 @@ NTSTATUS cli_raw_tcon(struct cli_state *cli,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 0, 0, True);
+       cli_set_message(cli->outbuf, 0, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBtcon);
        cli_setup_packet(cli);
 
index 76630bd50426d2b4843b3377466512ce9ce7078e..66c6ee10228f6f6afa25378ca1baf3fd50d700ec 100644 (file)
@@ -81,7 +81,7 @@ bool cli_send_mailslot(struct messaging_context *msg_ctx,
                return False;
        }
 
-       set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+       cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
        memcpy(ptr,tmp,4);
 
        SCVAL(ptr,smb_com,SMBtrans);
index 0544b3d879ce726a1133224cfd25e38f666025bd..da225ebc246dccea63005df712ecfeacc9f2d6a6 100644 (file)
 
 #include "includes.h"
 
+/*******************************************************************
+ Setup the word count and byte count for a client smb message.
+********************************************************************/
+
+int cli_set_message(char *buf,int num_words,int num_bytes,bool zero)
+{
+       if (zero && (num_words || num_bytes)) {
+               memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+       }
+       SCVAL(buf,smb_wct,num_words);
+       SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+       smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+       return (smb_size + num_words*2 + num_bytes);
+}
+
 /****************************************************************************
  Change the timeout (in milliseconds).
 ****************************************************************************/
@@ -85,7 +100,7 @@ bool cli_receive_smb(struct cli_state *cli)
 
        /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
        if (cli->fd == -1)
-               return False; 
+               return false; 
 
  again:
        len = client_receive_smb(cli, 0);
@@ -100,7 +115,7 @@ bool cli_receive_smb(struct cli_state *cli)
                                int fnum = SVAL(cli->inbuf,smb_vwv2);
                                unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
                                if (!cli->oplock_handler(cli, fnum, level)) {
-                                       return False;
+                                       return false;
                                }
                        }
                        /* try to prevent loops */
@@ -114,7 +129,7 @@ bool cli_receive_smb(struct cli_state *cli)
                 DEBUG(0, ("Receiving SMB: Server stopped responding\n"));
                close(cli->fd);
                cli->fd = -1;
-               return False;
+               return false;
        }
 
        if (!cli_check_sign_mac(cli)) {
@@ -135,16 +150,16 @@ bool cli_receive_smb(struct cli_state *cli)
                         * Set bad sig but don't close fd.
                         */
                        cli->smb_rw_error = SMB_READ_BAD_SIG;
-                       return True;
+                       return true;
                }
 
                DEBUG(0, ("SMB Signature verification failed on incoming packet!\n"));
                cli->smb_rw_error = SMB_READ_BAD_SIG;
                close(cli->fd);
                cli->fd = -1;
-               return False;
+               return false;
        };
-       return True;
+       return true;
 }
 
 /****************************************************************************
@@ -164,6 +179,7 @@ ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len)
 
 /****************************************************************************
  Read a smb readX header.
+ We can only use this if encryption and signing are off.
 ****************************************************************************/
 
 bool cli_receive_smb_readX_header(struct cli_state *cli)
@@ -171,7 +187,7 @@ bool cli_receive_smb_readX_header(struct cli_state *cli)
        ssize_t len, offset;
 
        if (cli->fd == -1)
-               return False; 
+               return false; 
 
  again:
 
@@ -199,7 +215,7 @@ bool cli_receive_smb_readX_header(struct cli_state *cli)
                        if (cli->oplock_handler) {
                                int fnum = SVAL(cli->inbuf,smb_vwv2);
                                unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
-                               if (!cli->oplock_handler(cli, fnum, level)) return False;
+                               if (!cli->oplock_handler(cli, fnum, level)) return false;
                        }
                        /* try to prevent loops */
                        SCVAL(cli->inbuf,smb_com,0xFF);
@@ -238,14 +254,14 @@ bool cli_receive_smb_readX_header(struct cli_state *cli)
                }
        }
 
-       return True;
+       return true;
 
   read_err:
 
        cli->smb_rw_error = SMB_READ_ERROR;
        close(cli->fd);
        cli->fd = -1;
-       return False;
+       return false;
 }
 
 static ssize_t write_socket(int fd, const char *buf, size_t len)
@@ -272,32 +288,54 @@ bool cli_send_smb(struct cli_state *cli)
        size_t len;
        size_t nwritten=0;
        ssize_t ret;
+       char *buf_out = cli->outbuf;
+       bool enc_on = cli_encryption_on(cli);
 
        /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
        if (cli->fd == -1)
-               return False;
+               return false;
 
        cli_calculate_sign_mac(cli);
 
-       len = smb_len(cli->outbuf) + 4;
+       if (enc_on) {
+               NTSTATUS status = cli_encrypt_message(cli, &buf_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       close(cli->fd);
+                       cli->fd = -1;
+                       cli->smb_rw_error = SMB_WRITE_ERROR;
+                       DEBUG(0,("Error in encrypting client message. Error %s\n",
+                               nt_errstr(status) ));
+                       return false;
+               }
+       }
+
+       len = smb_len(buf_out) + 4;
 
        while (nwritten < len) {
-               ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
+               ret = write_socket(cli->fd,buf_out+nwritten,len - nwritten);
                if (ret <= 0) {
+                       if (enc_on) {
+                               cli_free_enc_buffer(cli, buf_out);
+                       }
                        close(cli->fd);
                        cli->fd = -1;
                        cli->smb_rw_error = SMB_WRITE_ERROR;
                        DEBUG(0,("Error writing %d bytes to client. %d (%s)\n",
                                (int)len,(int)ret, strerror(errno) ));
-                       return False;
+                       return false;
                }
                nwritten += ret;
        }
+
+       if (enc_on) {
+               cli_free_enc_buffer(cli, buf_out);
+       }
+
        /* Increment the mid so we can tell between responses. */
        cli->mid++;
        if (!cli->mid)
                cli->mid++;
-       return True;
+       return true;
 }
 
 /****************************************************************************
@@ -347,7 +385,7 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli,
                        DEBUG(0,("Error writing %d extradata "
                                "bytes to client. %d (%s)\n",
                                (int)extradata,(int)ret, strerror(errno) ));
-                       return False;
+                       return false;
                }
                nwritten += ret;
        }
@@ -409,7 +447,7 @@ void cli_init_creds(struct cli_state *cli, const char *username, const char *dom
        fstrcpy(cli->user_name, username);
        pwd_set_cleartext(&cli->pwd, password);
        if (!*username) {
-               cli->pwd.null_pwd = True;
+               cli->pwd.null_pwd = true;
        }
 
         DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain));
@@ -424,16 +462,16 @@ void cli_setup_signing_state(struct cli_state *cli, int signing_state)
        if (signing_state == Undefined)
                return;
 
-       if (signing_state == False) {
-               cli->sign_info.allow_smb_signing = False;
-               cli->sign_info.mandatory_signing = False;
+       if (signing_state == false) {
+               cli->sign_info.allow_smb_signing = false;
+               cli->sign_info.mandatory_signing = false;
                return;
        }
 
-       cli->sign_info.allow_smb_signing = True;
+       cli->sign_info.allow_smb_signing = true;
 
        if (signing_state == Required) 
-               cli->sign_info.mandatory_signing = True;
+               cli->sign_info.mandatory_signing = true;
 }
 
 /****************************************************************************
@@ -470,7 +508,7 @@ struct cli_state *cli_initialise(void)
        cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
        cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
        cli->oplock_handler = cli_oplock_ack;
-       cli->case_sensitive = False;
+       cli->case_sensitive = false;
        cli->smb_rw_error = SMB_READ_OK;
 
        cli->use_spnego = lp_client_use_spnego();
@@ -481,13 +519,13 @@ struct cli_state *cli_initialise(void)
           client routines using DOS errors instead of STATUS32
           ones.  This intended only as a temporary hack. */    
        if (getenv("CLI_FORCE_DOSERR"))
-               cli->force_dos_errors = True;
+               cli->force_dos_errors = true;
 
        if (lp_client_signing()) 
-               cli->sign_info.allow_smb_signing = True;
+               cli->sign_info.allow_smb_signing = true;
 
        if (lp_client_signing() == Required) 
-               cli->sign_info.mandatory_signing = True;
+               cli->sign_info.mandatory_signing = true;
                                    
        if (!cli->outbuf || !cli->inbuf)
                 goto error;
@@ -522,7 +560,7 @@ struct cli_state *cli_initialise(void)
 /****************************************************************************
  External interface.
  Close an open named pipe over SMB. Free any authentication data.
- Returns False if the cli_close call failed.
+ Returns false if the cli_close call failed.
  ****************************************************************************/
 
 bool cli_rpc_pipe_close(struct rpc_pipe_client *cli)
@@ -530,7 +568,7 @@ bool cli_rpc_pipe_close(struct rpc_pipe_client *cli)
        bool ret;
 
        if (!cli) {
-               return False;
+               return false;
        }
 
        ret = cli_close(cli->cli, cli->fnum);
@@ -650,15 +688,15 @@ bool cli_send_keepalive(struct cli_state *cli)
 {
         if (cli->fd == -1) {
                 DEBUG(3, ("cli_send_keepalive: fd == -1\n"));
-                return False;
+                return false;
         }
         if (!send_keepalive(cli->fd)) {
                 close(cli->fd);
                 cli->fd = -1;
                 DEBUG(0,("Error sending keepalive packet to client.\n"));
-                return False;
+                return false;
         }
-        return True;
+        return true;
 }
 
 /****************************************************************************
@@ -674,7 +712,7 @@ bool cli_echo(struct cli_state *cli, uint16 num_echos,
        SMB_ASSERT(length < 1024);
 
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,1,length,True);
+       cli_set_message(cli->outbuf,1,length,true);
        SCVAL(cli->outbuf,smb_com,SMBecho);
        SSVAL(cli->outbuf,smb_tid,65535);
        SSVAL(cli->outbuf,smb_vwv0,num_echos);
@@ -689,13 +727,13 @@ bool cli_echo(struct cli_state *cli, uint16 num_echos,
 
        for (i=0; i<num_echos; i++) {
                if (!cli_receive_smb(cli)) {
-                       return False;
+                       return false;
                }
 
                if (cli_is_error(cli)) {
-                       return False;
+                       return false;
                }
        }
 
-       return True;
+       return true;
 }
index 001a42d4b9a244c32c119840f0555eaa55eddaa8..9b4c380d40705e74afddca0279ffbc4b00e08e05 100644 (file)
@@ -429,7 +429,7 @@ bool cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,1, 0, true);
+       cli_set_message(cli->outbuf,1, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBmv);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -470,7 +470,7 @@ bool cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fnam
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 4, 0, true);
+       cli_set_message(cli->outbuf, 4, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBntrename);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -512,7 +512,7 @@ bool cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *f
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 4, 0, true);
+       cli_set_message(cli->outbuf, 4, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBntrename);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -554,7 +554,7 @@ bool cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,1, 0, true);
+       cli_set_message(cli->outbuf,1, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBunlink);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -600,7 +600,7 @@ bool cli_mkdir(struct cli_state *cli, const char *dname)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,0, 0, true);
+       cli_set_message(cli->outbuf,0, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBmkdir);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -636,7 +636,7 @@ bool cli_rmdir(struct cli_state *cli, const char *dname)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,0, 0, true);
+       cli_set_message(cli->outbuf,0, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBrmdir);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -719,7 +719,7 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,24,0, true);
+       cli_set_message(cli->outbuf,24,0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBntcreateX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -815,7 +815,7 @@ int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,15,0, true);
+       cli_set_message(cli->outbuf,15,0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBopenX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -863,7 +863,7 @@ bool cli_close(struct cli_state *cli, int fnum)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,3,0,True);
+       cli_set_message(cli->outbuf,3,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBclose);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -896,7 +896,7 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0', smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -948,7 +948,7 @@ bool cli_lock(struct cli_state *cli, int fnum,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0', smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1001,7 +1001,7 @@ bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1053,7 +1053,7 @@ bool cli_lock64(struct cli_state *cli, int fnum,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0', smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1108,7 +1108,7 @@ bool cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1255,7 +1255,7 @@ bool cli_getattrE(struct cli_state *cli, int fd,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,1,0,True);
+       cli_set_message(cli->outbuf,1,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBgetattrE);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1307,7 +1307,7 @@ bool cli_getatr(struct cli_state *cli, const char *fname,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBgetatr);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1359,7 +1359,7 @@ bool cli_setattrE(struct cli_state *cli, int fd,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,7,0,True);
+       cli_set_message(cli->outbuf,7,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBsetattrE);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1398,7 +1398,7 @@ bool cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBsetatr);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1452,7 +1452,7 @@ bool cli_chkpath(struct cli_state *cli, const char *path)
        }
 
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
        SCVAL(cli->outbuf,smb_com,SMBcheckpath);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -1483,7 +1483,7 @@ bool cli_chkpath(struct cli_state *cli, const char *path)
 bool cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
 {
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
        SCVAL(cli->outbuf,smb_com,SMBdskattr);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -1512,7 +1512,7 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,3,0,True);
+       cli_set_message(cli->outbuf,3,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBctemp);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1565,7 +1565,7 @@ NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 3, 0, True);
+       cli_set_message(cli->outbuf, 3, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBioctl);
        cli_setup_packet(cli);
 
index 1a75d144b2aa3420aafc0da48600bfe4b2b0bc12..107613c618537552028c1d4a2036fd77dfe7d06e 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    FS info functions
    Copyright (C) Stefan (metze) Metzmacher     2003
+   Copyright (C) Jeremy Allison 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
@@ -301,3 +302,335 @@ cleanup:
 
        return ret;
 }
+
+/******************************************************************************
+ Send/receive the request encryption blob.
+******************************************************************************/
+
+static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
+{
+       uint16 setup;
+       char param[4];
+       char *rparam=NULL, *rdata=NULL;
+       unsigned int rparam_count=0, rdata_count=0;
+       NTSTATUS status = NT_STATUS_OK;
+
+       setup = TRANSACT2_SETFSINFO;
+
+       SSVAL(param,0,0);
+       SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
+
+       if (!cli_send_trans(cli, SMBtrans2,
+                               NULL,
+                               0, 0,
+                               &setup, 1, 0,
+                               param, 4, 0,
+                               (char *)in->data, in->length, CLI_BUFFER_SIZE)) {
+               status = cli_nt_error(cli);
+               goto out;
+       }
+
+       if (!cli_receive_trans(cli, SMBtrans2,
+                               &rparam, &rparam_count,
+                               &rdata, &rdata_count)) {
+               status = cli_nt_error(cli);
+               goto out;
+       }
+
+       if (cli_is_error(cli)) {
+               status = cli_nt_error(cli);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+                       goto out;
+               }
+       }
+
+       *out = data_blob(rdata, rdata_count);
+       *param_out = data_blob(rparam, rparam_count);
+
+  out:
+
+       SAFE_FREE(rparam);
+       SAFE_FREE(rdata);
+       return status;
+}
+
+/******************************************************************************
+ Make a client state struct.
+******************************************************************************/
+
+static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
+{
+       struct smb_trans_enc_state *es = NULL;
+       es = SMB_MALLOC_P(struct smb_trans_enc_state);
+       if (!es) {
+               return NULL;
+       }
+       ZERO_STRUCTP(es);
+       es->smb_enc_type = smb_enc_type;
+
+       if (smb_enc_type == SMB_TRANS_ENC_GSS) {
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+               es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
+               if (!es->s.gss_state) {
+                       SAFE_FREE(es);
+                       return NULL;
+               }
+               ZERO_STRUCTP(es->s.gss_state);
+#else
+               DEBUG(0,("make_cli_enc_state: no krb5 compiled.\n"));
+               SAFE_FREE(es);
+               return NULL;
+#endif
+       }
+       return es;
+}
+
+/******************************************************************************
+ Start a raw ntlmssp encryption.
+******************************************************************************/
+
+NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, 
+                               const char *user,
+                               const char *pass,
+                               const char *domain)
+{
+       DATA_BLOB blob_in = data_blob_null;
+       DATA_BLOB blob_out = data_blob_null;
+       DATA_BLOB param_out = data_blob_null;
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
+
+       if (!es) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       status = ntlmssp_client_start(&es->s.ntlmssp_state);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
+       es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
+
+       if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
+               goto fail;
+       }
+       if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
+               goto fail;
+       }
+       if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
+               goto fail;
+       }
+
+       do {
+               status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
+               data_blob_free(&blob_in);
+               data_blob_free(&param_out);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
+                       NTSTATUS trans_status = enc_blob_send_receive(cli,
+                                                                       &blob_out,
+                                                                       &blob_in,
+                                                                       &param_out);
+                       if (!NT_STATUS_EQUAL(trans_status,
+                                       NT_STATUS_MORE_PROCESSING_REQUIRED) &&
+                                       !NT_STATUS_IS_OK(trans_status)) {
+                               status = trans_status;
+                       } else {
+                               if (param_out.length == 2) {
+                                       es->enc_ctx_num = SVAL(param_out.data, 0);
+                               }
+                       }
+               }
+               data_blob_free(&blob_out);
+       } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+
+       data_blob_free(&blob_in);
+
+       if (NT_STATUS_IS_OK(status)) {
+               /* Replace the old state, if any. */
+               if (cli->trans_enc_state) {
+                       common_free_encryption_state(&cli->trans_enc_state);
+               }
+               cli->trans_enc_state = es;
+               cli->trans_enc_state->enc_on = True;
+               es = NULL;
+       }
+
+  fail:
+
+       common_free_encryption_state(&es);
+       return status;
+}
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+
+#ifndef SMB_GSS_REQUIRED_FLAGS
+#define SMB_GSS_REQUIRED_FLAGS (GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)
+#endif
+
+/******************************************************************************
+ Get client gss blob to send to a server.
+******************************************************************************/
+
+static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es,
+                               const char *service,
+                               const char *host,
+                               NTSTATUS status_in,
+                               DATA_BLOB spnego_blob_in,
+                               DATA_BLOB *p_blob_out)
+{
+       const char *krb_mechs[] = {OID_KERBEROS5, NULL};
+       OM_uint32 ret;
+       OM_uint32 min;
+       gss_name_t srv_name;
+       gss_buffer_desc input_name;
+       gss_buffer_desc *p_tok_in;
+       gss_buffer_desc tok_out, tok_in;
+       DATA_BLOB blob_out = data_blob_null;
+       DATA_BLOB blob_in = data_blob_null;
+       char *host_princ_s = NULL;
+       OM_uint32 ret_flags = 0;
+       NTSTATUS status = NT_STATUS_OK;
+
+       gss_OID_desc nt_hostbased_service =
+       {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
+
+       memset(&tok_out, '\0', sizeof(tok_out));
+
+       /* Get a ticket for the service@host */
+       asprintf(&host_princ_s, "%s@%s", service, host);
+       if (host_princ_s == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       input_name.value = host_princ_s;
+       input_name.length = strlen(host_princ_s) + 1;
+
+       ret = gss_import_name(&min,
+                               &input_name,
+                               &nt_hostbased_service,
+                               &srv_name);
+
+       if (ret != GSS_S_COMPLETE) {
+               SAFE_FREE(host_princ_s);
+               return map_nt_error_from_gss(ret, min);
+       }
+
+       if (spnego_blob_in.length == 0) {
+               p_tok_in = GSS_C_NO_BUFFER;
+       } else {
+               /* Remove the SPNEGO wrapper */
+               if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto fail;
+               }
+               tok_in.value = blob_in.data;
+               tok_in.length = blob_in.length;
+               p_tok_in = &tok_in;
+       }
+
+       ret = gss_init_sec_context(&min,
+                               GSS_C_NO_CREDENTIAL, /* Use our default cred. */
+                               &es->s.gss_state->gss_ctx,
+                               srv_name,
+                               GSS_C_NO_OID, /* default OID. */
+                               GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+                               GSS_C_INDEFINITE,       /* requested ticket lifetime. */
+                               NULL,   /* no channel bindings */
+                               p_tok_in,
+                               NULL,   /* ignore mech type */
+                               &tok_out,
+                               &ret_flags,
+                               NULL);  /* ignore time_rec */
+
+       status = map_nt_error_from_gss(ret, min);
+       if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
+               DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
+                       ads_errstr(adss)));
+               goto fail;
+       }
+
+       if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
+               status = NT_STATUS_ACCESS_DENIED;
+       }
+
+       blob_out = data_blob(tok_out.value, tok_out.length);
+
+       /* Wrap in an SPNEGO wrapper */
+       *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out);
+
+  fail:
+
+       data_blob_free(&blob_out);
+       data_blob_free(&blob_in);
+       SAFE_FREE(host_princ_s);
+       gss_release_name(&min, &srv_name);
+       if (tok_out.value) {
+               gss_release_buffer(&min, &tok_out);
+       }
+       return status;
+}
+
+/******************************************************************************
+ Start a SPNEGO gssapi encryption context.
+******************************************************************************/
+
+NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
+{
+       DATA_BLOB blob_recv = data_blob_null;
+       DATA_BLOB blob_send = data_blob_null;
+       DATA_BLOB param_out = data_blob_null;
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       fstring fqdn;
+       const char *servicename;
+       struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
+
+       if (!es) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       name_to_fqdn(fqdn, cli->desthost);
+       strlower_m(fqdn);
+
+       servicename = "cifs";
+       status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
+       if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               servicename = "host";
+               status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
+               if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+                       goto fail;
+               }
+       }
+
+       do {
+               data_blob_free(&blob_recv);
+               status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
+               if (param_out.length == 2) {
+                       es->enc_ctx_num = SVAL(param_out.data, 0);
+               }
+               data_blob_free(&blob_send);
+               status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send);
+       } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+       data_blob_free(&blob_recv);
+
+       if (NT_STATUS_IS_OK(status)) {
+               /* Replace the old state, if any. */
+               if (cli->trans_enc_state) {
+                       common_free_encryption_state(&cli->trans_enc_state);
+               }
+               cli->trans_enc_state = es;
+               cli->trans_enc_state->enc_on = True;
+               es = NULL;
+       }
+
+  fail:
+
+       common_free_encryption_state(&es);
+       return status;
+}
+#else
+NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+#endif
index 2e4c360507f610c3af851d7261f7d2b95b7f0bdd..d5c7db09e998c4dfd55962a82d3bd4c6bd03628c 100644 (file)
@@ -521,7 +521,7 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
                memset(cli->outbuf,'\0',smb_size);
                memset(cli->inbuf,'\0',smb_size);
 
-               set_message(cli->outbuf,2,0,True);
+               cli_set_message(cli->outbuf,2,0,True);
 
                SCVAL(cli->outbuf,smb_com,SMBsearch);
 
@@ -581,7 +581,7 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
                memset(cli->outbuf,'\0',smb_size);
                memset(cli->inbuf,'\0',smb_size);
 
-               set_message(cli->outbuf,2,0,True);
+               cli_set_message(cli->outbuf,2,0,True);
                SCVAL(cli->outbuf,smb_com,SMBfclose);
                SSVAL(cli->outbuf,smb_tid,cli->cnum);
                cli_setup_packet(cli);
index 13ef1d43d427e04c8340caa0ea1f1102ec61c5b7..00c25aa7254d3c365df91e77434ee936fd003661 100644 (file)
@@ -29,7 +29,7 @@ int cli_message_start_build(struct cli_state *cli, const char *host, const char
 
        /* construct a SMBsendstrt command */
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsendstrt);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -75,7 +75,7 @@ int cli_message_text_build(struct cli_state *cli, const char *msg, int len, int
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,1,0,True);
+       cli_set_message(cli->outbuf,1,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsendtxt);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -132,7 +132,7 @@ int cli_message_end_build(struct cli_state *cli, int grp)
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,1,0,True);
+       cli_set_message(cli->outbuf,1,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsendend);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
 
index 2e54f5a781b1fc5ba4c5e897bd40e1c7e3de8ea6..ef8b3964613ef9921403a5174866797f2b70e31c 100644 (file)
@@ -32,7 +32,7 @@ bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level)
        cli->outbuf = buf;
 
         memset(buf,'\0',smb_size);
-        set_message(buf,8,0,True);
+        cli_set_message(buf,8,0,True);
 
         SCVAL(buf,smb_com,SMBlockingX);
        SSVAL(buf,smb_tid, cli->cnum);
index 7fbdb97c016daaf7130b10d2ec0cef19f38e35c5..223ddb41866e3ee294fede75f9e6cc858e660acf 100644 (file)
@@ -195,7 +195,7 @@ int cli_spl_open(struct cli_state *cli, const char *fname, int flags, int share_
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,15,0,True);
+       cli_set_message(cli->outbuf,15,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBsplopen);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -242,7 +242,7 @@ bool cli_spl_close(struct cli_state *cli, int fnum)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,3,0,True);
+       cli_set_message(cli->outbuf,3,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBsplclose);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
index d77875bae52f3b0e5144b82e8c583a03aa138bdb..0b33e43563377119e1fb528c2d17590f67a792e9 100644 (file)
@@ -34,7 +34,7 @@ static bool cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
        if ((SMB_BIG_UINT)offset >> 32)
                bigoffset = True;
 
-       set_message(cli->outbuf,bigoffset ? 12 : 10,0,True);
+       cli_set_message(cli->outbuf,bigoffset ? 12 : 10,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBreadX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -65,8 +65,8 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
        size_t size2;
        size_t readsize;
        ssize_t total = 0;
-       /* We can only do direct reads if not signing. */
-       bool direct_reads = !client_is_signing_on(cli);
+       /* We can only do direct reads if not signing or encrypting. */
+       bool direct_reads = !client_is_signing_on(cli) && !cli_encryption_on(cli);
 
        if (size == 0)
                return 0;
@@ -76,7 +76,9 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
         * rounded down to a multiple of 1024.
         */
 
-       if (client_is_signing_on(cli) == False && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) {
+       if (client_is_signing_on(cli) == false &&
+                       cli_encryption_on(cli) == false &&
+                       (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) {
                readsize = CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE;
        } else if (cli->capabilities & CAP_LARGE_READX) {
                if (cli->is_samba) {
@@ -203,7 +205,7 @@ static bool cli_issue_readraw(struct cli_state *cli, int fnum, off_t offset,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,10,0,True);
+       cli_set_message(cli->outbuf,10,0,True);
                
        SCVAL(cli->outbuf,smb_com,SMBreadbraw);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -295,8 +297,8 @@ static bool cli_issue_write(struct cli_state *cli,
 {
        char *p;
        bool large_writex = false;
-       /* We can only do direct writes if not signing. */
-       bool direct_writes = !client_is_signing_on(cli);
+       /* We can only do direct writes if not signing and not encrypting. */
+       bool direct_writes = !client_is_signing_on(cli) && !cli_encryption_on(cli);
 
        if (!direct_writes && size + 1 > cli->bufsize) {
                cli->outbuf = (char *)SMB_REALLOC(cli->outbuf, size + 1024);
@@ -319,9 +321,9 @@ static bool cli_issue_write(struct cli_state *cli,
        }
 
        if (large_writex) {
-               set_message(cli->outbuf,14,0,True);
+               cli_set_message(cli->outbuf,14,0,True);
        } else {
-               set_message(cli->outbuf,12,0,True);
+               cli_set_message(cli->outbuf,12,0,True);
        }
 
        SCVAL(cli->outbuf,smb_com,SMBwriteX);
@@ -404,16 +406,17 @@ ssize_t cli_write(struct cli_state *cli,
 
         if (write_mode == 0 &&
                        !client_is_signing_on(cli) &&
+                       !cli_encryption_on(cli) &&
                        (cli->posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) &&
                        (cli->capabilities & CAP_LARGE_FILES)) {
                /* Only do massive writes if we can do them direct
-                * with no signing - not on a pipe. */
+                * with no signing or encrypting - not on a pipe. */
                writesize = CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE;
-       } else if (cli->capabilities & CAP_LARGE_READX) {
+       } else if (cli->capabilities & CAP_LARGE_WRITEX) {
                if (cli->is_samba) {
-                       writesize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
+                       writesize = CLI_SAMBA_MAX_LARGE_WRITEX_SIZE;
                } else {
-                       writesize = CLI_WINDOWS_MAX_LARGE_READX_SIZE;
+                       writesize = CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE;
                }
        } else {
                writesize = (cli->max_xmit - (smb_size+32)) & ~1023;
@@ -471,7 +474,7 @@ ssize_t cli_smbwrite(struct cli_state *cli,
                memset(cli->outbuf,'\0',smb_size);
                memset(cli->inbuf,'\0',smb_size);
 
-               set_message(cli->outbuf,5, 0,True);
+               cli_set_message(cli->outbuf,5, 0,True);
 
                SCVAL(cli->outbuf,smb_com,SMBwrite);
                SSVAL(cli->outbuf,smb_tid,cli->cnum);
index a6f7f7fec1972117bf6d665725853eed8012f959..bfb31fdb74845a1a2908942dfaee5eaee14b9075 100644 (file)
@@ -43,7 +43,7 @@ bool cli_send_trans(struct cli_state *cli, int trans,
        this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
 
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,14+lsetup,0,True);
+       cli_set_message(cli->outbuf,14+lsetup,0,True);
        SCVAL(cli->outbuf,smb_com,trans);
        SSVAL(cli->outbuf,smb_tid, cli->cnum);
        cli_setup_packet(cli);
@@ -107,7 +107,7 @@ bool cli_send_trans(struct cli_state *cli, int trans,
                        this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
                        this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
 
-                       set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
+                       cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
                        SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
 
                        outparam = smb_buf(cli->outbuf);
@@ -368,7 +368,7 @@ bool cli_send_nt_trans(struct cli_state *cli,
        this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
 
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,19+lsetup,0,True);
+       cli_set_message(cli->outbuf,19+lsetup,0,True);
        SCVAL(cli->outbuf,smb_com,SMBnttrans);
        SSVAL(cli->outbuf,smb_tid, cli->cnum);
        cli_setup_packet(cli);
@@ -424,7 +424,7 @@ bool cli_send_nt_trans(struct cli_state *cli,
                        this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
                        this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
 
-                       set_message(cli->outbuf,18,0,True);
+                       cli_set_message(cli->outbuf,18,0,True);
                        SCVAL(cli->outbuf,smb_com,SMBnttranss);
 
                        /* XXX - these should probably be aligned */
index ce826ae999ec34bd84969ccd78ae50b97ac3e4ca..4ec30f7e17f0d23d89a89390c882c3aa3be5b363 100644 (file)
@@ -1502,3 +1502,108 @@ WERROR ntstatus_to_werror(NTSTATUS error)
        /* a lame guess */
        return W_ERROR(NT_STATUS_V(error) & 0xffff);
 }
+
+#if defined(HAVE_GSSAPI)
+/*******************************************************************************
+ Map between gssapi errors and NT status. I made these up :-(. JRA.
+*******************************************************************************/
+
+static const struct {
+               unsigned long gss_err;
+               NTSTATUS ntstatus;
+} gss_to_ntstatus_errormap[] = {
+#if defined(GSS_S_CALL_INACCESSIBLE_READ)
+               {GSS_S_CALL_INACCESSIBLE_READ, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_CALL_INACCESSIBLE_WRITE)
+               {GSS_S_CALL_INACCESSIBLE_WRITE, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_CALL_BAD_STRUCTURE)
+               {GSS_S_CALL_BAD_STRUCTURE, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_MECH)
+               {GSS_S_BAD_MECH, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_NAME)
+               {GSS_S_BAD_NAME, NT_STATUS_INVALID_ACCOUNT_NAME},
+#endif
+#if defined(GSS_S_BAD_NAMETYPE)
+               {GSS_S_BAD_NAMETYPE, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_BINDINGS)
+               {GSS_S_BAD_BINDINGS, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_STATUS)
+               {GSS_S_BAD_STATUS, NT_STATUS_UNSUCCESSFUL},
+#endif
+#if defined(GSS_S_BAD_SIG)
+               {GSS_S_BAD_SIG, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_NO_CRED)
+               {GSS_S_NO_CRED, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_NO_CONTEXT)
+               {GSS_S_NO_CONTEXT, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_DEFECTIVE_TOKEN)
+               {GSS_S_DEFECTIVE_TOKEN, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_DEFECTIVE_CREDENTIAL)
+               {GSS_S_DEFECTIVE_CREDENTIAL, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_CREDENTIALS_EXPIRED)
+               {GSS_S_CREDENTIALS_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+#endif
+#if defined(GSS_S_CONTEXT_EXPIRED)
+               {GSS_S_CONTEXT_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+#endif
+#if defined(GSS_S_BAD_QOP)
+               {GSS_S_BAD_QOP, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_UNAUTHORIZED)
+               {GSS_S_UNAUTHORIZED, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_UNAVAILABLE)
+               {GSS_S_UNAVAILABLE, NT_STATUS_UNSUCCESSFUL},
+#endif
+#if defined(GSS_S_DUPLICATE_ELEMENT)
+               {GSS_S_DUPLICATE_ELEMENT, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_NAME_NOT_MN)
+               {GSS_S_NAME_NOT_MN, NT_STATUS_INVALID_PARAMETER},
+#endif
+               { 0, NT_STATUS_OK }
+};
+
+/*********************************************************************
+ Map an NT error code from a gssapi error code.
+*********************************************************************/
+
+NTSTATUS map_nt_error_from_gss(uint32 gss_maj, uint32 minor)
+{
+       int i = 0;
+
+       if (gss_maj == GSS_S_COMPLETE) {
+               return NT_STATUS_OK;
+       }
+
+       if (gss_maj == GSS_S_CONTINUE_NEEDED) {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
+
+       if (gss_maj == GSS_S_FAILURE) {
+               return map_nt_error_from_unix((int)minor);
+       }
+       
+       /* Look through list */
+       while(gss_to_ntstatus_errormap[i].gss_err != 0) {
+               if (gss_to_ntstatus_errormap[i].gss_err == gss_maj) {
+                       return gss_to_ntstatus_errormap[i].ntstatus;
+               }
+               i++;
+       }
+
+       /* Default return */
+       return NT_STATUS_ACCESS_DENIED;
+}
+#endif
diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c
new file mode 100644 (file)
index 0000000..055a27d
--- /dev/null
@@ -0,0 +1,496 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB Transport encryption (sealing) code.
+   Copyright (C) Jeremy Allison 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
+   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,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/******************************************************************************
+ Pull out the encryption context for this packet. 0 means global context.
+******************************************************************************/
+
+NTSTATUS get_enc_ctx_num(const char *buf, uint16 *p_enc_ctx_num)
+{
+       if (smb_len(buf) < 8) {
+               return NT_STATUS_INVALID_BUFFER_SIZE;
+       }
+
+       if (buf[4] == (char)0xFF) {
+               if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
+                       /* Not an encrypted buffer. */
+                       return NT_STATUS_NOT_FOUND;
+               }
+               if (buf[5] == 'E') {
+                       *p_enc_ctx_num = SVAL(buf,6);
+                       return NT_STATUS_OK;
+               }
+       }
+       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Is encryption turned on ?
+******************************************************************************/
+
+bool common_encryption_on(struct smb_trans_enc_state *es)
+{
+       return ((es != NULL) && es->enc_on);
+}
+
+/******************************************************************************
+ 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. */
+       data_len = buf_len - 8 - NTLMSSP_SIG_SIZE;
+
+       /* Point at the signature. */
+       sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE);
+
+       status = ntlmssp_unseal_packet(ntlmssp_state,
+               (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)) {
+               SAFE_FREE(inbuf);
+               return status;
+       }
+
+       memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
+
+       /* Reset the length. */
+       _smb_setlen(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,
+                               uint16 enc_ctx_num,
+                               char *buf,
+                               char **ppbuf_out)
+{
+       NTSTATUS status;
+       char *buf_out;
+       size_t data_len = smb_len(buf) - 4; /* Ignore the 0xFF SMB bytes. */
+       DATA_BLOB sig;
+
+       *ppbuf_out = NULL;
+
+       if (data_len == 0) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       /* 
+        * We know smb_len can't return a value > 128k, so no int overflow
+        * check needed.
+        */
+
+       buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len);
+
+       /* Copy the data from the original buffer. */
+
+       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 + 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)) {
+               data_blob_free(&sig);
+               SAFE_FREE(buf_out);
+               return status;
+       }
+
+       /* 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;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ gss-api decrypt an incoming buffer. We insist that the size of the
+ unwrapped buffer must be smaller or identical to the incoming buffer.
+******************************************************************************/
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+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;
+       OM_uint32 minor = 0;
+       int flags_got = 0;
+       gss_buffer_desc in_buf, out_buf;
+       size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+
+       if (buf_len < 8) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       in_buf.value = buf + 8;
+       in_buf.length = buf_len - 8;
+
+       ret = gss_unwrap(&minor,
+                       gss_ctx,
+                       &in_buf,
+                       &out_buf,
+                       &flags_got,             /* did we get sign+seal ? */
+                       (gss_qop_t *) NULL);    
+
+       if (ret != GSS_S_COMPLETE) {
+               ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
+               DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
+                       ads_errstr(adss) ));
+               return map_nt_error_from_gss(ret, minor);
+       }
+
+       if (out_buf.length > in_buf.length) {
+               DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
+                       (unsigned int)out_buf.length,
+                       (unsigned int)in_buf.length ));
+               gss_release_buffer(&minor, &out_buf);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       memcpy(buf + 8, out_buf.value, out_buf.length);
+       _smb_setlen(buf, out_buf.length + 4);
+
+       gss_release_buffer(&minor, &out_buf);
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
+******************************************************************************/
+
+static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
+                                       uint16 enc_ctx_num,
+                                       char *buf,
+                                       char **ppbuf_out)
+{
+       gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
+       OM_uint32 ret = 0;
+       OM_uint32 minor = 0;
+       int flags_got = 0;
+       gss_buffer_desc in_buf, out_buf;
+       size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+
+       *ppbuf_out = NULL;
+
+       if (buf_len < 8) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       in_buf.value = buf + 8;
+       in_buf.length = buf_len - 8;
+
+       ret = gss_wrap(&minor,
+                       gss_ctx,
+                       true,                   /* we want sign+seal. */
+                       GSS_C_QOP_DEFAULT,
+                       &in_buf,
+                       &flags_got,             /* did we get sign+seal ? */
+                       &out_buf);
+
+       if (ret != GSS_S_COMPLETE) {
+               ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
+               DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
+                       ads_errstr(adss) ));
+               return map_nt_error_from_gss(ret, minor);
+       }
+
+       if (!flags_got) {
+               /* Sign+seal not supported. */
+               gss_release_buffer(&minor, &out_buf);
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       /* Ya see - this is why I *hate* gss-api. I don't 
+        * want to have to malloc another buffer of the
+        * same size + 8 bytes just to get a continuous
+        * header + buffer, but gss won't let me pass in
+        * a pre-allocated buffer. Bastards (and you know
+        * who you are....). I might fix this by
+        * going to "encrypt_and_send" passing in a file
+        * descriptor and doing scatter-gather write with
+        * TCP cork on Linux. But I shouldn't have to
+        * bother :-*(. JRA.
+        */
+
+       *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;
+       }
+
+       memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
+       smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
+
+       gss_release_buffer(&minor, &out_buf);
+       return NT_STATUS_OK;
+}
+#endif
+
+/******************************************************************************
+ Generic code for client and server.
+ Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
+{
+       if (!common_encryption_on(es)) {
+               /* Not encrypting. */
+               *buf_out = buffer;
+               return NT_STATUS_OK;
+       }
+
+       switch (es->smb_enc_type) {
+               case SMB_TRANS_ENC_NTLM:
+                       return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, es->enc_ctx_num, buffer, buf_out);
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+               case SMB_TRANS_ENC_GSS:
+                       return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
+#endif
+               default:
+                       return NT_STATUS_NOT_SUPPORTED;
+       }
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Decrypt an incoming SMB buffer. Replaces the data within it.
+ New data must be less than or equal to the current length.
+******************************************************************************/
+
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+       if (!common_encryption_on(es)) {
+               /* Not decrypting. */
+               return NT_STATUS_OK;
+       }
+
+       switch (es->smb_enc_type) {
+               case SMB_TRANS_ENC_NTLM:
+                       return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+               case SMB_TRANS_ENC_GSS:
+                       return common_gss_decrypt_buffer(es->s.gss_state, buf);
+#endif
+               default:
+                       return NT_STATUS_NOT_SUPPORTED;
+       }
+}
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+/******************************************************************************
+ Shutdown a gss encryption state.
+******************************************************************************/
+
+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;
+
+       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
+
+/******************************************************************************
+ Shutdown an encryption state.
+******************************************************************************/
+
+void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
+{
+       struct smb_trans_enc_state *es = *pp_es;
+
+       if (es == NULL) {
+               return;
+       }
+
+       if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
+               if (es->s.ntlmssp_state) {
+                       ntlmssp_end(&es->s.ntlmssp_state);
+               }
+       }
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+       if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
+               /* Free the gss context handle. */
+               if (es->s.gss_state) {
+                       common_free_gss_state(&es->s.gss_state);
+               }
+       }
+#endif
+       SAFE_FREE(es);
+       *pp_es = NULL;
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+       if (!common_encryption_on(es)) {
+               return;
+       }
+
+       if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
+               SAFE_FREE(buf);
+               return;
+       }
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+       if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
+               OM_uint32 min;
+               gss_buffer_desc rel_buf;
+               rel_buf.value = buf;
+               rel_buf.length = smb_len(buf) + 4;
+               gss_release_buffer(&min, &rel_buf);
+       }
+#endif
+}
+
+/******************************************************************************
+ Client side encryption.
+******************************************************************************/
+
+/******************************************************************************
+ Is client encryption on ?
+******************************************************************************/
+
+bool cli_encryption_on(struct cli_state *cli)
+{
+       /* If we supported multiple encrytion contexts
+        * here we'd look up based on tid.
+        */
+       return common_encryption_on(cli->trans_enc_state);
+}
+
+/******************************************************************************
+ Shutdown a client encryption state.
+******************************************************************************/
+
+void cli_free_encryption_context(struct cli_state *cli)
+{
+       common_free_encryption_state(&cli->trans_enc_state);
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void cli_free_enc_buffer(struct cli_state *cli, char *buf)
+{
+       /* We know this is an smb buffer, and we
+        * didn't malloc, only copy, for a keepalive,
+        * so ignore session keepalives. */
+
+       if(CVAL(buf,0) == SMBkeepalive) {
+               return;
+       }
+
+       /* If we supported multiple encrytion contexts
+        * here we'd look up based on tid.
+        */
+       common_free_enc_buffer(cli->trans_enc_state, buf);
+}
+
+/******************************************************************************
+ Decrypt an incoming buffer.
+******************************************************************************/
+
+NTSTATUS cli_decrypt_message(struct cli_state *cli)
+{
+       NTSTATUS status;
+       uint16 enc_ctx_num;
+
+       /* Ignore session keepalives. */
+       if(CVAL(cli->inbuf,0) == SMBkeepalive) {
+               return NT_STATUS_OK;
+       }
+
+       status = get_enc_ctx_num(cli->inbuf, &enc_ctx_num);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
+}
+
+/******************************************************************************
+ Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
+{
+       /* Ignore session keepalives. */
+       if(CVAL(cli->outbuf,0) == SMBkeepalive) {
+               return NT_STATUS_OK;
+       }
+
+       /* If we supported multiple encrytion contexts
+        * here we'd look up based on tid.
+        */
+       return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);
+}
index 349d36ce70df1a5d2ccc3e888076a4962273b3a3..3bb151420343fbf3a5114bea0681125d27b5797a 100644 (file)
@@ -1924,7 +1924,7 @@ bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t len,
                return false;
        }
 
-       set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+       cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
        memcpy(ptr,tmp,4);
 
        SCVAL(ptr,smb_com,SMBtrans);
index 5b009fc964d5d3736b6b82e7f80a914420ac8c3b..7186d4f075492402901e2dafd911d624809093c6 100644 (file)
@@ -6209,7 +6209,7 @@ uint32 lp_get_spoolss_state( void )
 }
 
 /*******************************************************************
- Ensure we don't use sendfile if server smb signing is active.
+ Ensure we don't use sendfile if server smb signing or selaing is active.
 ********************************************************************/
 
 bool lp_use_sendfile(int snum)
@@ -6218,7 +6218,10 @@ bool lp_use_sendfile(int snum)
        if (Protocol < PROTOCOL_NT1) {
                return False;
        }
-       return (_lp_use_sendfile(snum) && (get_remote_arch() != RA_WIN95) && !srv_is_signing_active());
+       return (_lp_use_sendfile(snum) &&
+                       (get_remote_arch() != RA_WIN95) &&
+                       !srv_is_signing_active() &&
+                       !srv_encryption_on());
 }
 
 /*******************************************************************
index 994b10d6a813bb3468c73c032a0e040b7eaa114c..f13393b7648d2063c2ad0e1ecce2209429ac073b 100644 (file)
@@ -236,7 +236,7 @@ bool schedule_aio_read_and_X(connection_struct *conn,
        }
 
        construct_reply_common((char *)req->inbuf, aio_ex->outbuf);
-       set_message(aio_ex->outbuf, 12, 0, True);
+       srv_set_message((const char *)req->inbuf, aio_ex->outbuf, 12, 0, True);
        SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
 
        a = &aio_ex->acb;
@@ -387,6 +387,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
        int ret = 0;
        int outsize;
        char *outbuf = aio_ex->outbuf;
+       const char *inbuf = aio_ex->inbuf;
        char *data = smb_buf(outbuf);
        ssize_t nread = SMB_VFS_AIO_RETURN(aio_ex->fsp,&aio_ex->acb);
 
@@ -407,10 +408,11 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
                           "Error = %s\n",
                           aio_ex->fsp->fsp_name, strerror(errno) ));
 
-               outsize = (UNIXERROR(ERRDOS,ERRnoaccess));
                ret = errno;
+               ERROR_NT(map_nt_error_from_unix(ret));
+               outsize = srv_set_message(inbuf,outbuf,0,0,true);
        } else {
-               outsize = set_message(outbuf,12,nread,False);
+               outsize = srv_set_message(inbuf, outbuf,12,nread,False);
                SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be * -1. */
                SSVAL(outbuf,smb_vwv5,nread);
                SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
@@ -423,7 +425,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
                            (int)aio_ex->acb.aio_nbytes, (int)nread ) );
 
        }
-       smb_setlen(outbuf,outsize - 4);
+       _smb_setlen(outbuf,outsize - 4);
        show_msg(outbuf);
        if (!send_smb(smbd_server_fd(),outbuf)) {
                exit_server_cleanly("handle_aio_read_complete: send_smb "
@@ -448,6 +450,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
        int ret = 0;
        files_struct *fsp = aio_ex->fsp;
        char *outbuf = aio_ex->outbuf;
+       const char *inbuf = aio_ex->inbuf;
        ssize_t numtowrite = aio_ex->acb.aio_nbytes;
        ssize_t nwritten = SMB_VFS_AIO_RETURN(fsp,&aio_ex->acb);
 
@@ -492,8 +495,9 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                        return 0;
                }
 
-               UNIXERROR(ERRHRD,ERRdiskfull);
                ret = errno;
+               ERROR_BOTH(ERRHRD, ERRdiskfull, map_nt_error_from_unix(ret));
+               srv_set_message(inbuf,outbuf,0,0,true);
         } else {
                bool write_through = BITSETW(aio_ex->inbuf+smb_vwv7,0);
                NTSTATUS status;
@@ -509,8 +513,9 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                         fsp->fnum, (int)numtowrite, (int)nwritten));
                status = sync_file(fsp->conn,fsp, write_through);
                if (!NT_STATUS_IS_OK(status)) {
-                       UNIXERROR(ERRHRD,ERRdiskfull);
                        ret = errno;
+                       ERROR_BOTH(ERRHRD, ERRdiskfull, map_nt_error_from_unix(ret));
+                       srv_set_message(inbuf,outbuf,0,0,true);
                        DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n",
                                fsp->fsp_name, nt_errstr(status) ));
                }
index 12eff42023a5facd65683c66f8a486349847b121..c669e741461536ec687629b4952c188c8fabbae7 100644 (file)
@@ -24,34 +24,6 @@ extern struct unix_error_map unix_dos_nt_errmap[];
 
 extern uint32 global_client_caps;
 
-/****************************************************************************
- Create an error packet from errno.
-****************************************************************************/
-
-int unix_error_packet(char *outbuf,int def_class,uint32 def_code, NTSTATUS def_status, int line, const char *file)
-{
-       int eclass=def_class;
-       int ecode=def_code;
-       NTSTATUS ntstatus = def_status;
-       int i=0;
-
-       if (errno != 0) {
-               DEBUG(3,("unix_error_packet: error string = %s\n",strerror(errno)));
-  
-               while (unix_dos_nt_errmap[i].dos_class != 0) {
-                       if (unix_dos_nt_errmap[i].unix_error == errno) {
-                               eclass = unix_dos_nt_errmap[i].dos_class;
-                               ecode = unix_dos_nt_errmap[i].dos_code;
-                               ntstatus = unix_dos_nt_errmap[i].nt_error;
-                               break;
-                       }
-                       i++;
-               }
-       }
-
-       return error_packet(outbuf,eclass,ecode,ntstatus,line,file);
-}
-
 bool use_nt_status(void)
 {
        return lp_nt_status_support() && (global_client_caps & CAP_STATUS32);
@@ -109,9 +81,9 @@ void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatu
        }
 }
 
-int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
+int error_packet(const char *inbuf, char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
 {
-       int outsize = set_message(outbuf,0,0,True);
+       int outsize = srv_set_message(inbuf, outbuf,0,0,True);
        error_packet_set(outbuf, eclass, ecode, ntstatus, line, file);
        return outsize;
 }
@@ -150,8 +122,24 @@ void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
                         line, file);
 }
 
+void reply_openerror(struct smb_request *req, NTSTATUS status)
+{
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+               /*
+                * We hit an existing file, and if we're returning DOS
+                * error codes OBJECT_NAME_COLLISION would map to
+                * ERRDOS/183, we need to return ERRDOS/80, see bug
+                * 4852.
+                */
+               reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
+                       ERRDOS, ERRfilexists);
+       } else {
+               reply_nterror(req, status);
+       }
+}
+
 void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
-                     NTSTATUS defstatus, int line, const char *file)
+                       NTSTATUS defstatus, int line, const char *file)
 {
        int eclass=defclass;
        int ecode=defcode;
@@ -163,7 +151,7 @@ void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
 
        if (errno != 0) {
                DEBUG(3,("unix_error_packet: error string = %s\n",
-                        strerror(errno)));
+                       strerror(errno)));
 
                while (unix_dos_nt_errmap[i].dos_class != 0) {
                        if (unix_dos_nt_errmap[i].unix_error == errno) {
@@ -177,22 +165,5 @@ void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
        }
 
        error_packet_set((char *)req->outbuf, eclass, ecode, ntstatus,
-                        line, file);
+               line, file);
 }
-
-void reply_openerror(struct smb_request *req, NTSTATUS status)
-{
-       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
-               /*
-                * We hit an existing file, and if we're returning DOS
-                * error codes OBJECT_NAME_COLLISION would map to
-                * ERRDOS/183, we need to return ERRDOS/80, see bug
-                * 4852.
-                */
-               reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
-                       ERRDOS, ERRfilexists);
-       } else {
-               reply_nterror(req, status);
-       }
-}
-
index 0dd7fbb20e912ce8be7d45048a5dfe0ec8f0ede1..baab48f77ef4713865bc7b27a003c9c77abc122d 100644 (file)
@@ -131,6 +131,7 @@ static bool notify_marshall_changes(int num_changes,
 static void change_notify_reply_packet(const uint8 *request_buf,
                                       NTSTATUS error_code)
 {
+       const char *inbuf = (const char *)request_buf;
        char outbuf[smb_size+38];
 
        memset(outbuf, '\0', sizeof(outbuf));
@@ -142,7 +143,7 @@ static void change_notify_reply_packet(const uint8 *request_buf,
         * Seems NT needs a transact command with an error code
         * in it. This is a longer packet than a simple error.
         */
-       set_message(outbuf,18,0,False);
+       srv_set_message((const char *)request_buf, outbuf,18,0,False);
 
        show_msg(outbuf);
        if (!send_smb(smbd_server_fd(),outbuf))
index 961abd277b4384c841c9358e584a234726125b71..2c3313606a0495f667d63dc4ee56b486fa656792 100644 (file)
@@ -252,7 +252,11 @@ static char *new_break_smb_message(TALLOC_CTX *mem_ctx,
        }
 
        memset(result,'\0',smb_size);
-       set_message(result,8,0,True);
+       /* We use cli_set_message here as this is an
+        * asynchronous message that doesn't belong in
+        * the stream.
+        */
+       cli_set_message(result,8,0,True);
        SCVAL(result,smb_com,SMBlockingX);
        SSVAL(result,smb_tid,fsp->conn->cnum);
        SSVAL(result,smb_pid,0xFFFF);
index 0ddc00c7676d06dfc0fd1d0369cff91ed7c82a1a..88b67c03e57aa658d6248df315b0c85e6a5b60ff 100644 (file)
@@ -291,7 +291,8 @@ void reply_pipe_read_and_X(struct smb_request *req)
                return;
        }
 
-       set_message((char *)req->outbuf, 12, nread, False);
+       srv_set_message((const char *)req->inbuf,
+               (char *)req->outbuf, 12, nread, False);
   
        SSVAL(req->outbuf,smb_vwv5,nread);
        SSVAL(req->outbuf,smb_vwv6,smb_offset(data,req->outbuf));
index ee76f90bf512b493979393c42b5f301f0395345b..1260d52c7717a5ca761557926f70563bf8965854 100644 (file)
@@ -50,6 +50,43 @@ enum smb_read_errors *get_srv_read_error(void)
        return &smb_read_error;
 }
 
+/*******************************************************************
+ Setup the word count and byte count for a smb message.
+ copying the '0xFF X X X' bytes from incoming
+ buffer (so we copy any encryption context).
+********************************************************************/
+
+int srv_set_message(const char *frombuf,
+                        char *buf,
+                        int num_words,
+                        int num_bytes,
+                        bool zero)
+{
+       if (zero && (num_words || num_bytes)) {
+               memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+       }
+       SCVAL(buf,smb_wct,num_words);
+       SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+       _smb_setlen(buf,(smb_size + num_words*2 + num_bytes - 4));
+       if (buf != frombuf) {
+               memcpy(buf+4, frombuf+4, 4);
+       }
+       return (smb_size + num_words*2 + num_bytes);
+}
+
+static bool valid_smb_header(const char *inbuf)
+{
+       if (srv_encryption_on()) {
+               uint16_t enc_num;
+               NTSTATUS status = get_enc_ctx_num(inbuf, &enc_num);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return false;
+               }
+               return (enc_num == 0);
+       }
+       return (strncmp(smb_base(inbuf),"\377SMB",4) == 0);
+}
+
 /* Socket functions for smbd packet processing. */
 
 static bool valid_packet_size(size_t len)
@@ -324,6 +361,18 @@ ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer,
                return -1;
        }
 
+       if (srv_encryption_on()) {
+               NTSTATUS status = srv_decrypt_buffer(*buffer);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("receive_smb_talloc: SMB decryption failed on "
+                               "incoming packet! Error %s\n",
+                               nt_errstr(status) ));
+                       cond_set_smb_read_error(get_srv_read_error(),
+                                       SMB_READ_BAD_DECRYPT);
+                       return -1;
+               }
+       }
+
        /* Check the incoming SMB signature. */
        if (!srv_check_sign_mac(*buffer, true)) {
                DEBUG(0, ("receive_smb: SMB Signature verification failed on "
@@ -1239,7 +1288,8 @@ void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes)
        }
 
        construct_reply_common((char *)req->inbuf, (char *)req->outbuf);
-       set_message((char *)req->outbuf, num_words, num_bytes, False);
+       srv_set_message((const char *)req->inbuf,
+                       (char *)req->outbuf, num_words, num_bytes, false);
        /*
         * Zero out the word area, the caller has to take care of the bcc area
         * himself
@@ -1309,7 +1359,7 @@ static void switch_message(uint8 type, struct smb_request *req, int size)
 
        /* Make sure this is an SMB packet. smb_size contains NetBIOS header
         * so subtract 4 from it. */
-       if ((strncmp(smb_base(req->inbuf),"\377SMB",4) != 0)
+       if (!valid_smb_header((const char *)req->inbuf)
            || (size < (smb_size - 4))) {
                DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
                         smb_len(req->inbuf)));
@@ -1551,7 +1601,7 @@ void remove_from_common_flags2(uint32 v)
 
 void construct_reply_common(const char *inbuf, char *outbuf)
 {
-       set_message(outbuf,0,0,False);
+       srv_set_message(inbuf,outbuf,0,0,false);
        
        SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
        SIVAL(outbuf,smb_rcls,0);
index 575ca13ff685c31d5b9dfa5fcf08a554ed2fe613..2707aee9c821b15d2a3c7e339aee7b6bc309879d 100644 (file)
@@ -2791,8 +2791,8 @@ void reply_readbraw(connection_struct *conn, struct smb_request *req)
 
        START_PROFILE(SMBreadbraw);
 
-       if (srv_is_signing_active()) {
-               exit_server_cleanly("reply_readbraw: SMB signing is active - "
+       if (srv_is_signing_active() || srv_encryption_on()) {
+               exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
                        "raw reads/writes are disallowed.");
        }
 
@@ -3017,7 +3017,8 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
                return;
        }
        
-       set_message((char *)req->outbuf, 5, nread+3, False);
+       srv_set_message((const char *)req->inbuf,
+               (char *)req->outbuf, 5, nread+3, False);
 
        SSVAL(req->outbuf,smb_vwv0,nread);
        SSVAL(req->outbuf,smb_vwv5,nread+3);
@@ -3104,7 +3105,8 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
                return;
        }
 
-       set_message((char *)req->outbuf, 5, nread+3, False);
+       srv_set_message((const char *)req->inbuf,
+               (char *)req->outbuf, 5, nread+3, False);
 
        SSVAL(req->outbuf,smb_vwv0,nread);
        SSVAL(req->outbuf,smb_vwv5,nread+3);
@@ -3122,12 +3124,12 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
  Setup readX header.
 ****************************************************************************/
 
-static int setup_readX_header(char *outbuf, size_t smb_maxcnt)
+static int setup_readX_header(const char *inbuf, char *outbuf, size_t smb_maxcnt)
 {
        int outsize;
        char *data;
 
-       outsize = set_message(outbuf,12,smb_maxcnt,False);
+       outsize = srv_set_message(inbuf, outbuf,12,smb_maxcnt,False);
        data = smb_buf(outbuf);
 
        memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
@@ -3190,7 +3192,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
                header = data_blob_const(headerbuf, sizeof(headerbuf));
 
                construct_reply_common((char *)req->inbuf, (char *)headerbuf);
-               setup_readX_header((char *)headerbuf, smb_maxcnt);
+               setup_readX_header((const char *)req->inbuf,
+                       (char *)headerbuf, smb_maxcnt);
 
                if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, smb_maxcnt)) == -1) {
                        /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
@@ -3241,7 +3244,8 @@ normal_read:
                uint8 headerbuf[smb_size + 2*12];
 
                construct_reply_common((char *)req->inbuf, (char *)headerbuf);
-               setup_readX_header((char *)headerbuf, smb_maxcnt);
+               setup_readX_header((const char *)req->inbuf,
+                       (char *)headerbuf, smb_maxcnt);
 
                /* Send out the header. */
                if (write_data(smbd_server_fd(), (char *)headerbuf,
@@ -3268,7 +3272,8 @@ normal_read:
                        return;
                }
 
-               setup_readX_header((char *)req->outbuf, nread);
+               setup_readX_header((const char *)req->inbuf,
+                       (char *)req->outbuf, nread);
 
                DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
                        fsp->fnum, (int)smb_maxcnt, (int)nread ) );
@@ -3332,8 +3337,8 @@ void reply_read_and_X(connection_struct *conn, struct smb_request *req)
                                END_PROFILE(SMBreadX);
                                return;
                        }
-                       /* We currently don't do this on signed data. */
-                       if (srv_is_signing_active()) {
+                       /* We currently don't do this on signed or sealed data. */
+                       if (srv_is_signing_active() || srv_encryption_on()) {
                                reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
                                END_PROFILE(SMBreadX);
                                return;
@@ -3524,7 +3529,7 @@ void reply_writebraw(connection_struct *conn, struct smb_request *req)
         * it to send more bytes */
 
        memcpy(buf, req->inbuf, smb_size);
-       outsize = set_message(buf,
+       outsize = srv_set_message((const char *)req->inbuf, buf,
                        Protocol>PROTOCOL_COREPLUS?1:0,0,True);
        SCVAL(buf,smb_com,SMBwritebraw);
        SSVALS(buf,smb_vwv0,0xFFFF);
@@ -3856,6 +3861,12 @@ bool is_valid_writeX_buffer(const char *inbuf)
        unsigned int doff = 0;
        size_t len = smb_len_large(inbuf);
 
+       if (srv_encryption_on()) {
+               /* Can't do this on encrypted
+                * connections. */
+               return false;
+       }
+
        if (CVAL(inbuf,smb_com) != SMBwriteX) {
                return false;
        }
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
new file mode 100644 (file)
index 0000000..14a427b
--- /dev/null
@@ -0,0 +1,703 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB Transport encryption (sealing) code - server code.
+   Copyright (C) Jeremy Allison 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
+   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,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/******************************************************************************
+ Server side encryption.
+******************************************************************************/
+
+/******************************************************************************
+ Global server state.
+******************************************************************************/
+
+struct smb_srv_trans_enc_ctx {
+       struct smb_trans_enc_state *es;
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state; /* Must be kept in sync with pointer in ec->ntlmssp_state. */
+};
+
+static struct smb_srv_trans_enc_ctx *partial_srv_trans_enc_ctx;
+static struct smb_srv_trans_enc_ctx *srv_trans_enc_ctx;
+
+/******************************************************************************
+ Is server encryption on ?
+******************************************************************************/
+
+bool srv_encryption_on(void)
+{
+       if (srv_trans_enc_ctx) {
+               return common_encryption_on(srv_trans_enc_ctx->es);
+       }
+       return false;
+}
+
+/******************************************************************************
+ Create an auth_ntlmssp_state and ensure pointer copy is correct.
+******************************************************************************/
+
+static NTSTATUS make_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec)
+{
+       NTSTATUS status = auth_ntlmssp_start(&ec->auth_ntlmssp_state);
+       if (!NT_STATUS_IS_OK(status)) {
+               return nt_status_squash(status);
+       }
+
+       /*
+        * We must remember to update the pointer copy for the common
+        * functions after any auth_ntlmssp_start/auth_ntlmssp_end.
+        */
+       ec->es->s.ntlmssp_state = ec->auth_ntlmssp_state->ntlmssp_state;
+       return status;
+}
+
+/******************************************************************************
+ Destroy an auth_ntlmssp_state and ensure pointer copy is correct.
+******************************************************************************/
+
+static void destroy_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec)
+{
+       /*
+        * We must remember to update the pointer copy for the common
+        * functions after any auth_ntlmssp_start/auth_ntlmssp_end.
+        */
+
+       if (ec->auth_ntlmssp_state) {
+               auth_ntlmssp_end(&ec->auth_ntlmssp_state);
+               /* The auth_ntlmssp_end killed this already. */
+               ec->es->s.ntlmssp_state = NULL;
+       }
+}
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+
+/******************************************************************************
+ Import a name.
+******************************************************************************/
+
+static NTSTATUS get_srv_gss_creds(const char *service,
+                               const char *name,
+                               gss_cred_usage_t cred_type,
+                               gss_cred_id_t *p_srv_cred)
+{
+       OM_uint32 ret;
+       OM_uint32 min;
+       gss_name_t srv_name;
+       gss_buffer_desc input_name;
+       char *host_princ_s = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+
+       gss_OID_desc nt_hostbased_service =
+       {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
+
+       asprintf(&host_princ_s, "%s@%s", service, name);
+       if (host_princ_s == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       input_name.value = host_princ_s;
+       input_name.length = strlen(host_princ_s) + 1;
+
+       ret = gss_import_name(&min,
+                               &input_name,
+                               &nt_hostbased_service,
+                               &srv_name);
+
+       DEBUG(10,("get_srv_gss_creds: imported name %s\n",
+               host_princ_s ));
+
+       if (ret != GSS_S_COMPLETE) {
+               SAFE_FREE(host_princ_s);
+               return map_nt_error_from_gss(ret, min);
+       }
+
+       /*
+        * We're accessing the krb5.keytab file here.
+        * ensure we have permissions to do so.
+        */
+       become_root();
+
+       ret = gss_acquire_cred(&min,
+                               srv_name,
+                               GSS_C_INDEFINITE,
+                               GSS_C_NULL_OID_SET,
+                               cred_type,
+                               p_srv_cred,
+                               NULL,
+                               NULL);
+       unbecome_root();
+
+       if (ret != GSS_S_COMPLETE) {
+               ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
+               DEBUG(10,("get_srv_gss_creds: gss_acquire_cred failed with %s\n",
+                       ads_errstr(adss)));
+               status = map_nt_error_from_gss(ret, min);
+       }
+
+       SAFE_FREE(host_princ_s);
+       gss_release_name(&min, &srv_name);
+       return status;
+}
+
+/******************************************************************************
+ Create a gss state.
+ Try and get the cifs/server@realm principal first, then fall back to
+ host/server@realm.
+******************************************************************************/
+
+static NTSTATUS make_auth_gss(struct smb_srv_trans_enc_ctx *ec)
+{
+       NTSTATUS status;
+       gss_cred_id_t srv_cred;
+       fstring fqdn;
+
+       name_to_fqdn(fqdn, global_myname());
+       strlower_m(fqdn);
+
+       status = get_srv_gss_creds("cifs", fqdn, GSS_C_ACCEPT, &srv_cred);
+       if (!NT_STATUS_IS_OK(status)) {
+               status = get_srv_gss_creds("host", fqdn, GSS_C_ACCEPT, &srv_cred);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return nt_status_squash(status);
+               }
+       }
+
+       ec->es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
+       if (!ec->es->s.gss_state) {
+               OM_uint32 min;
+               gss_release_cred(&min, &srv_cred);
+               return NT_STATUS_NO_MEMORY;
+       }
+       ZERO_STRUCTP(ec->es->s.gss_state);
+       ec->es->s.gss_state->creds = srv_cred;
+
+       /* No context yet. */
+       ec->es->s.gss_state->gss_ctx = GSS_C_NO_CONTEXT;
+
+       return NT_STATUS_OK;
+}
+#endif
+
+/******************************************************************************
+ Shutdown a server encryption context.
+******************************************************************************/
+
+static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec)
+{
+       struct smb_srv_trans_enc_ctx *ec = *pp_ec;
+
+       if (!ec) {
+               return;
+       }
+
+       if (ec->es) {
+               switch (ec->es->smb_enc_type) {
+                       case SMB_TRANS_ENC_NTLM:
+                               destroy_auth_ntlmssp(ec);
+                               break;
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+                       case SMB_TRANS_ENC_GSS:
+                               break;
+#endif
+               }
+               common_free_encryption_state(&ec->es);
+       }
+
+       SAFE_FREE(ec);
+       *pp_ec = NULL;
+}
+
+/******************************************************************************
+ Create a server encryption context.
+******************************************************************************/
+
+static NTSTATUS make_srv_encryption_context(enum smb_trans_enc_type smb_enc_type, struct smb_srv_trans_enc_ctx **pp_ec)
+{
+       struct smb_srv_trans_enc_ctx *ec;
+
+       *pp_ec = NULL;
+
+       ec = SMB_MALLOC_P(struct smb_srv_trans_enc_ctx);
+       if (!ec) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       ZERO_STRUCTP(partial_srv_trans_enc_ctx);
+       ec->es = SMB_MALLOC_P(struct smb_trans_enc_state);
+       if (!ec->es) {
+               SAFE_FREE(ec);
+               return NT_STATUS_NO_MEMORY;
+       }
+       ZERO_STRUCTP(ec->es);
+       ec->es->smb_enc_type = smb_enc_type;
+       switch (smb_enc_type) {
+               case SMB_TRANS_ENC_NTLM:
+                       {
+                               NTSTATUS status = make_auth_ntlmssp(ec);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       srv_free_encryption_context(&ec);
+                                       return status;
+                               }
+                       }
+                       break;
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+               case SMB_TRANS_ENC_GSS:
+                       /* Acquire our credentials by calling gss_acquire_cred here. */
+                       {
+                               NTSTATUS status = make_auth_gss(ec);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       srv_free_encryption_context(&ec);
+                                       return status;
+                               }
+                       }
+                       break;
+#endif
+               default:
+                       srv_free_encryption_context(&ec);
+                       return NT_STATUS_INVALID_PARAMETER;
+       }
+       *pp_ec = ec;
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void srv_free_enc_buffer(char *buf)
+{
+       /* We know this is an smb buffer, and we
+        * didn't malloc, only copy, for a keepalive,
+        * so ignore session keepalives. */
+
+       if(CVAL(buf,0) == SMBkeepalive) {
+               return;
+       }
+
+       if (srv_trans_enc_ctx) {
+               common_free_enc_buffer(srv_trans_enc_ctx->es, buf);
+       }
+}
+
+/******************************************************************************
+ Decrypt an incoming buffer.
+******************************************************************************/
+
+NTSTATUS srv_decrypt_buffer(char *buf)
+{
+       /* Ignore session keepalives. */
+       if(CVAL(buf,0) == SMBkeepalive) {
+               return NT_STATUS_OK;
+       }
+
+       if (srv_trans_enc_ctx) {
+               return common_decrypt_buffer(srv_trans_enc_ctx->es, buf);
+       }
+
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS srv_encrypt_buffer(char *buf, char **buf_out)
+{
+       *buf_out = buf;
+
+       /* Ignore session keepalives. */
+       if(CVAL(buf,0) == SMBkeepalive) {
+               return NT_STATUS_OK;
+       }
+
+       if (srv_trans_enc_ctx) {
+               return common_encrypt_buffer(srv_trans_enc_ctx->es, buf, buf_out);
+       }
+       /* Not encrypting. */
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Do the gss encryption negotiation. Parameters are in/out.
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob)
+{
+       OM_uint32 ret;
+       OM_uint32 min;
+       OM_uint32 flags = 0;
+       gss_buffer_desc in_buf, out_buf;
+       struct smb_tran_enc_state_gss *gss_state;
+       DATA_BLOB auth_reply = data_blob_null;
+       DATA_BLOB response = data_blob_null;
+       NTSTATUS status;
+
+       if (!partial_srv_trans_enc_ctx) {
+               status = make_srv_encryption_context(SMB_TRANS_ENC_GSS, &partial_srv_trans_enc_ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
+       gss_state = partial_srv_trans_enc_ctx->es->s.gss_state;
+
+       in_buf.value = secblob.data;
+       in_buf.length = secblob.length;
+
+       out_buf.value = NULL;
+       out_buf.length = 0;
+
+       become_root();
+
+       ret = gss_accept_sec_context(&min,
+                               &gss_state->gss_ctx,
+                               gss_state->creds,
+                               &in_buf,
+                               GSS_C_NO_CHANNEL_BINDINGS,
+                               NULL,
+                               NULL,           /* Ignore oids. */
+                               &out_buf,       /* To return. */
+                               &flags,
+                               NULL,           /* Ingore time. */
+                               NULL);          /* Ignore delegated creds. */
+       unbecome_root();
+
+       status = gss_err_to_ntstatus(ret, min);
+       if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
+               return status;
+       }
+
+       /* Ensure we've got sign+seal available. */
+       if (ret == GSS_S_COMPLETE) {
+               if ((flags & (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) !=
+                               (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) {
+                       DEBUG(0,("srv_enc_spnego_gss_negotiate: quality of service not good enough "
+                               "for SMB sealing.\n"));
+                       gss_release_buffer(&min, &out_buf);
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+       }
+
+       auth_reply = data_blob(out_buf.value, out_buf.length);
+       gss_release_buffer(&min, &out_buf);
+
+       /* Wrap in SPNEGO. */
+       response = spnego_gen_auth_response(&auth_reply, status, OID_KERBEROS5);
+       data_blob_free(&auth_reply);
+
+       SAFE_FREE(*ppdata);
+       *ppdata = response.data;
+       *p_data_size = response.length;
+
+       return status;
+}
+#endif
+
+/******************************************************************************
+ Do the NTLM SPNEGO (or raw) encryption negotiation. Parameters are in/out.
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+static NTSTATUS srv_enc_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob, bool spnego_wrap)
+{
+       NTSTATUS status;
+       DATA_BLOB chal = data_blob_null;
+       DATA_BLOB response = data_blob_null;
+
+       status = make_srv_encryption_context(SMB_TRANS_ENC_NTLM, &partial_srv_trans_enc_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, secblob, &chal);
+
+       /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
+        * for success ... */
+
+       if (spnego_wrap) {
+               response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP);
+               data_blob_free(&chal);
+       } else {
+               /* Return the raw blob. */
+               response = chal;
+       }
+
+       SAFE_FREE(*ppdata);
+       *ppdata = response.data;
+       *p_data_size = response.length;
+       return status;
+}
+
+/******************************************************************************
+ Do the SPNEGO encryption negotiation. Parameters are in/out.
+ Based off code in smbd/sesssionsetup.c
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
+                                       unsigned char **ppdata,
+                                       size_t *p_data_size,
+                                       unsigned char **pparam,
+                                       size_t *p_param_size)
+{
+       NTSTATUS status;
+       DATA_BLOB blob = data_blob_null;
+       DATA_BLOB secblob = data_blob_null;
+       bool got_kerberos_mechanism = false;
+
+       blob = data_blob_const(*ppdata, *p_data_size);
+
+       status = parse_spnego_mechanisms(blob, &secblob, &got_kerberos_mechanism);
+       if (!NT_STATUS_IS_OK(status)) {
+               return nt_status_squash(status);
+       }
+
+       /* We should have no partial context at this point. */
+
+       srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+       if (got_kerberos_mechanism && lp_use_kerberos_keytab() ) {
+               status = srv_enc_spnego_gss_negotiate(ppdata, p_data_size, secblob);
+       } else 
+#endif
+       {
+               status = srv_enc_ntlm_negotiate(ppdata, p_data_size, secblob, true);
+       }
+
+       data_blob_free(&secblob);
+
+       if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
+               srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+               return nt_status_squash(status);
+       }
+
+       if (NT_STATUS_IS_OK(status)) {
+               /* Return the context we're using for this encryption state. */
+               if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               SSVAL(*pparam,0,partial_srv_trans_enc_ctx->es->enc_ctx_num);
+               *p_param_size = 2;
+       }
+
+       return status;
+}
+
+/******************************************************************************
+ Complete a SPNEGO encryption negotiation. Parameters are in/out.
+ We only get this for a NTLM auth second stage.
+******************************************************************************/
+
+static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
+                                       unsigned char **ppdata,
+                                       size_t *p_data_size,
+                                       unsigned char **pparam,
+                                       size_t *p_param_size)
+{
+       NTSTATUS status;
+       DATA_BLOB blob = data_blob_null;
+       DATA_BLOB auth = data_blob_null;
+       DATA_BLOB auth_reply = data_blob_null;
+       DATA_BLOB response = data_blob_null;
+       struct smb_srv_trans_enc_ctx *ec = partial_srv_trans_enc_ctx;
+
+       /* We must have a partial context here. */
+
+       if (!ec || !ec->es || ec->auth_ntlmssp_state == NULL || ec->es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
+               srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       blob = data_blob_const(*ppdata, *p_data_size);
+       if (!spnego_parse_auth(blob, &auth)) {
+               srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       status = auth_ntlmssp_update(ec->auth_ntlmssp_state, auth, &auth_reply);
+       data_blob_free(&auth);
+
+       response = spnego_gen_auth_response(&auth_reply, status, OID_NTLMSSP);
+       data_blob_free(&auth_reply);
+
+       if (NT_STATUS_IS_OK(status)) {
+               /* Return the context we're using for this encryption state. */
+               if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               SSVAL(*pparam,0,ec->es->enc_ctx_num);
+               *p_param_size = 2;
+       }
+
+       SAFE_FREE(*ppdata);
+       *ppdata = response.data;
+       *p_data_size = response.length;
+       return status;
+}
+
+/******************************************************************************
+ Raw NTLM encryption negotiation. Parameters are in/out.
+ This function does both steps.
+******************************************************************************/
+
+static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
+                                       unsigned char **ppdata,
+                                       size_t *p_data_size,
+                                       unsigned char **pparam,
+                                       size_t *p_param_size)
+{
+       NTSTATUS status;
+       DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
+       DATA_BLOB response = data_blob_null;
+       struct smb_srv_trans_enc_ctx *ec;
+
+       if (!partial_srv_trans_enc_ctx) {
+               /* This is the initial step. */
+               status = srv_enc_ntlm_negotiate(ppdata, p_data_size, blob, false);
+               if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
+                       srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+                       return nt_status_squash(status);
+               }
+               return status;
+       }
+
+       ec = partial_srv_trans_enc_ctx;
+       if (!ec || !ec->es || ec->auth_ntlmssp_state == NULL || ec->es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
+               srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* Second step. */
+       status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, blob, &response);
+
+       if (NT_STATUS_IS_OK(status)) {
+               /* Return the context we're using for this encryption state. */
+               if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               SSVAL(*pparam,0,ec->es->enc_ctx_num);
+               *p_param_size = 2;
+       }
+
+       /* Return the raw blob. */
+       SAFE_FREE(*ppdata);
+       *ppdata = response.data;
+       *p_data_size = response.length;
+       return status;
+}
+
+/******************************************************************************
+ Do the SPNEGO encryption negotiation. Parameters are in/out.
+******************************************************************************/
+
+NTSTATUS srv_request_encryption_setup(connection_struct *conn,
+                                       unsigned char **ppdata,
+                                       size_t *p_data_size,
+                                       unsigned char **pparam,
+                                       size_t *p_param_size)
+{
+       unsigned char *pdata = *ppdata;
+
+       SAFE_FREE(*pparam);
+       *p_param_size = 0;
+
+       if (*p_data_size < 1) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (pdata[0] == ASN1_APPLICATION(0)) {
+               /* its a negTokenTarg packet */
+               return srv_enc_spnego_negotiate(conn, ppdata, p_data_size, pparam, p_param_size);
+       }
+
+       if (pdata[0] == ASN1_CONTEXT(1)) {
+               /* It's an auth packet */
+               return srv_enc_spnego_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
+       }
+
+       /* Maybe it's a raw unwrapped auth ? */
+       if (*p_data_size < 7) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (strncmp((char *)pdata, "NTLMSSP", 7) == 0) {
+               return srv_enc_raw_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
+       }
+
+       DEBUG(1,("srv_request_encryption_setup: Unknown packet\n"));
+
+       return NT_STATUS_LOGON_FAILURE;
+}
+
+/******************************************************************************
+ Negotiation was successful - turn on server-side encryption.
+******************************************************************************/
+
+static NTSTATUS check_enc_good(struct smb_srv_trans_enc_ctx *ec)
+{
+       if (!ec || !ec->es) {
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       if (ec->es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
+               if ((ec->es->s.ntlmssp_state->neg_flags & (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL)) !=
+                               (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL)) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       }
+       /* Todo - check gssapi case. */
+
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Negotiation was successful - turn on server-side encryption.
+******************************************************************************/
+
+NTSTATUS srv_encryption_start(connection_struct *conn)
+{
+       NTSTATUS status;
+
+       /* Check that we are really doing sign+seal. */
+       status = check_enc_good(partial_srv_trans_enc_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       /* Throw away the context we're using currently (if any). */
+       srv_free_encryption_context(&srv_trans_enc_ctx);
+
+       /* Steal the partial pointer. Deliberate shallow copy. */
+       srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
+       srv_trans_enc_ctx->es->enc_on = true;
+
+       partial_srv_trans_enc_ctx = NULL;
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Shutdown all server contexts.
+******************************************************************************/
+
+void server_encryption_shutdown(void)
+{
+       srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+       srv_free_encryption_context(&srv_trans_enc_ctx);
+}
index e37f6ffbfd0393d42e2d2a2fa223985ea20a9dac..0e34284443581ac465108b1733887c5e30ee71f2 100644 (file)
@@ -2998,6 +2998,55 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                                }
                                break;
                        }
+
+               case SMB_REQUEST_TRANSPORT_ENCRYPTION:
+                       {
+                               NTSTATUS status;
+                               size_t param_len = 0;
+                               size_t data_len = total_data;
+
+                               if (!lp_unix_extensions()) {
+                                       reply_nterror(
+                                               req,
+                                               NT_STATUS_INVALID_LEVEL);
+                                       return;
+                               }
+
+                               DEBUG( 4,("call_trans2setfsinfo: "
+                                       "request transport encrption.\n"));
+
+                               status = srv_request_encryption_setup(conn,
+                                                               (unsigned char **)ppdata,
+                                                               &data_len,
+                                                               (unsigned char **)pparams,
+                                                               &param_len);
+
+                               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
+                                               !NT_STATUS_IS_OK(status)) {
+                                       reply_nterror(req, status);
+                                       return;
+                               }
+
+                               send_trans2_replies(req,
+                                               *pparams,
+                                               param_len,
+                                               *ppdata,
+                                               data_len,
+                                               max_data_bytes);
+
+                               if (NT_STATUS_IS_OK(status)) {
+                                       /* Server-side transport
+                                        * encryption is now *on*. */
+                                       status = srv_encryption_start(conn);
+                                       if (!NT_STATUS_IS_OK(status)) {
+                                               exit_server_cleanly(
+                                                       "Failure in setting "
+                                                       "up encrypted transport");
+                                       }
+                               }
+                               return;
+                       }
+
                case SMB_FS_QUOTA_INFORMATION:
                        {
                                files_struct *fsp = NULL;