1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

Add SMB encryption. Still fixing client decrypt but

negotiation works.
Jeremy.
(This used to be commit d78045601a)
This commit is contained in:
Jeremy Allison 2007-12-26 17:12:36 -08:00
parent 23c965d947
commit afc93255d1
34 changed files with 2127 additions and 225 deletions

View 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 \

View 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}},

View 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;

View 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

View File

@ -158,11 +158,10 @@
#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__)
@ -170,9 +169,6 @@
#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
@ -189,8 +185,8 @@
#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; \

View 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

View 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;
}

View File

@ -604,6 +604,19 @@ void show_msg(char *buf)
dump_data(10, (uint8 *)smb_buf(buf), bcc);
}
/*******************************************************************
Set the length and marker of an encrypted smb packet.
********************************************************************/
void smb_set_enclen(char *buf,int len,uint16 enc_ctx_num)
{
_smb_setlen(buf,len);
SCVAL(buf,4,0xFF);
SCVAL(buf,5,'E');
SSVAL(buf,6,enc_ctx_num);
}
/*******************************************************************
Set the length and marker of an smb packet.
********************************************************************/
@ -618,21 +631,6 @@ void smb_setlen(char *buf,int len)
SCVAL(buf,7,'B');
}
/*******************************************************************
Setup the word count and byte count for a smb message.
********************************************************************/
int 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);
}
/*******************************************************************
Setup only the byte count for a smb message.
********************************************************************/
@ -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

View 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);
len = smb_len(buffer) + 4;
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(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;
}

View 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

View 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);

View 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);

View File

@ -20,6 +20,21 @@
#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;
}

View 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);

View 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

View 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);

View 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);

View 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);

View 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);

View 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);

View 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 */

View 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

496
source3/libsmb/smb_seal.c Normal file
View File

@ -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);
}

View 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);

View 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());
}
/*******************************************************************

View 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) ));
}

View 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,36 +122,6 @@ void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
line, file);
}
void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
NTSTATUS defstatus, int line, const char *file)
{
int eclass=defclass;
int ecode=defcode;
NTSTATUS ntstatus = defstatus;
int i=0;
TALLOC_FREE(req->outbuf);
reply_outbuf(req, 0, 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++;
}
}
error_packet_set((char *)req->outbuf, eclass, ecode, ntstatus,
line, file);
}
void reply_openerror(struct smb_request *req, NTSTATUS status)
{
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
@ -196,3 +138,32 @@ void reply_openerror(struct smb_request *req, NTSTATUS status)
}
}
void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
NTSTATUS defstatus, int line, const char *file)
{
int eclass=defclass;
int ecode=defcode;
NTSTATUS ntstatus = defstatus;
int i=0;
TALLOC_FREE(req->outbuf);
reply_outbuf(req, 0, 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++;
}
}
error_packet_set((char *)req->outbuf, eclass, ecode, ntstatus,
line, file);
}

View 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))

View 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);

View 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));

View 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);

View 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;
}

703
source3/smbd/seal.c Normal file
View File

@ -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);
}

View 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;