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:
parent
23c965d947
commit
afc93255d1
@ -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 \
|
||||
|
@ -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}},
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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; \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(¶m_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,
|
||||
¶m_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, ¶m_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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
496
source3/libsmb/smb_seal.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
|
@ -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) ));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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
703
source3/smbd/seal.c
Normal 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);
|
||||
}
|
@ -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,
|
||||
¶m_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;
|
||||
|
Loading…
Reference in New Issue
Block a user