From 9254bb4ef1c3c3a52ea8e935edb0e7a86ec3ea7a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2008 12:56:23 -0800 Subject: Refactor the crypto code after a very helpful conversation with Volker. Mostly making sure we have data on the incoming packet type, not stored in the smb header. Jeremy. (This used to be commit c4e5a505043965eec77b5bb9bc60957e8f3b97c8) --- source3/client/client.c | 10 ++- source3/include/smb.h | 4 + source3/include/smb_macros.h | 11 ++- source3/lib/dummysmbd.c | 21 ----- source3/lib/util_sock.c | 74 ------------------ source3/libsmb/smb_seal.c | 25 +++--- source3/libsmb/smb_signing.c | 8 +- source3/param/loadparm.c | 5 +- source3/printing/nt_printing.c | 2 +- source3/smbd/aio.c | 27 +++---- source3/smbd/blocking.c | 34 ++++---- source3/smbd/error.c | 4 +- source3/smbd/ipc.c | 53 +++++++------ source3/smbd/lanman.c | 2 +- source3/smbd/notify.c | 46 ++++++----- source3/smbd/nttrans.c | 39 ++++++---- source3/smbd/open.c | 4 +- source3/smbd/oplock.c | 26 +++---- source3/smbd/pipes.c | 3 +- source3/smbd/process.c | 173 +++++++++++++++++++++++++++-------------- source3/smbd/reply.c | 55 ++++++------- source3/smbd/seal.c | 44 +++++++---- source3/smbd/sesssetup.c | 2 +- source3/smbd/trans2.c | 69 +++++++++------- source3/utils/smbfilter.c | 28 ++++++- 25 files changed, 410 insertions(+), 359 deletions(-) (limited to 'source3') diff --git a/source3/client/client.c b/source3/client/client.c index 2a86035cf0..fbcfa531ed 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -4328,16 +4328,22 @@ static void readline_callback(void) timeout.tv_usec = 0; sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout); - /* We deliberately use receive_smb instead of + /* We deliberately use receive_smb_raw instead of client_receive_smb as we want to receive session keepalives and then drop them here. */ if (FD_ISSET(cli->fd,&fds)) { - if (!receive_smb(cli->fd,cli->inbuf,0,&cli->smb_rw_error)) { + if (!receive_smb_raw(cli->fd,cli->inbuf,0,0,&cli->smb_rw_error)) { DEBUG(0, ("Read from server failed, maybe it closed the " "connection\n")); return; } + if(CVAL(cli->inbuf,0) != SMBkeepalive) { + DEBUG(0, ("Read from server " + "returned unexpected packet!\n")); + return; + } + goto again; } diff --git a/source3/include/smb.h b/source3/include/smb.h index 75fe31e041..49245eaa83 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -659,6 +659,7 @@ typedef struct connection_struct { int num_files_open; unsigned int num_smb_operations; /* Count of smb operations on this tree. */ int encrypt_level; + bool encrypted_tid; /* Semantics requested by the client or forced by the server config. */ bool case_sensitive; @@ -694,6 +695,8 @@ struct smb_request { const uint8 *inbuf; uint8 *outbuf; size_t unread_bytes; + bool encrypted; + connection_struct *conn; }; /* Defines for the sent_oplock_break field above. */ @@ -757,6 +760,7 @@ struct pending_message_list { struct pending_message_list *next, *prev; struct timeval request_time; /* When was this first issued? */ struct timeval end_time; /* When does this time out? */ + bool encrypted; DATA_BLOB buf; DATA_BLOB private_data; }; diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index 9bacdce1db..3324f3fc02 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -158,10 +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(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 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_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 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__) @@ -192,6 +192,9 @@ #define _smb_setlen_large(buf,len) do { buf[0] = 0; buf[1] = ((len)&0xFF0000)>>16; \ buf[2] = ((len)&0xFF00)>>8; buf[3] = (len)&0xFF; } while (0) +#define ENCRYPTION_REQUIRED(conn) ((conn) ? ((conn)->encrypt_level == Required) : false) +#define IS_CONN_ENCRYPTED(conn) ((conn) ? (conn)->encrypted_tid : false) + /******************************************************************* find the difference in milliseconds between two struct timeval values diff --git a/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c index 464ba92306..dbe886e3d1 100644 --- a/source3/lib/dummysmbd.c +++ b/source3/lib/dummysmbd.c @@ -51,24 +51,3 @@ 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; -} diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index b92cd3d624..945506ea77 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -1276,80 +1276,6 @@ ssize_t receive_smb_raw(int fd, return len; } -/**************************************************************************** - Wrapper for receive_smb_raw(). - Checks the MAC on signed packets. -****************************************************************************/ - -bool receive_smb(int fd, char *buffer, unsigned int timeout, enum smb_read_errors *pre) -{ - if (receive_smb_raw(fd, buffer, timeout, 0, pre) < 0) { - 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 " - "failed on incoming packet!\n")); - cond_set_smb_read_error(pre,SMB_READ_BAD_SIG); - return false; - } - - return true; -} - -/**************************************************************************** - Send an smb to a fd. -****************************************************************************/ - -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(buf_out); - - if (srv_encryption_on()) { - NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("send_smb: SMB encryption failed " - "on outgoing packet! Error %s\n", - nt_errstr(status) )); - return false; - } - } - - len = smb_len(buf_out) + 4; - - while (nwritten < len) { - 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; -} - /**************************************************************************** Open a socket of the specified type, port, and address for incoming data. ****************************************************************************/ diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c index 055a27d05a..b5befbf7cd 100644 --- a/source3/libsmb/smb_seal.c +++ b/source3/libsmb/smb_seal.c @@ -23,13 +23,13 @@ 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) +NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num) { if (smb_len(buf) < 8) { return NT_STATUS_INVALID_BUFFER_SIZE; } - if (buf[4] == (char)0xFF) { + if (buf[4] == 0xFF) { if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') { /* Not an encrypted buffer. */ return NT_STATUS_NOT_FOUND; @@ -93,8 +93,8 @@ NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf) memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len); - /* Reset the length. */ - _smb_setlen(buf,data_len + 4); + /* Reset the length and overwrite the header. */ + smb_setlen(buf,data_len + 4); SAFE_FREE(inbuf); return NT_STATUS_OK; @@ -203,7 +203,8 @@ static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_sta } memcpy(buf + 8, out_buf.value, out_buf.length); - _smb_setlen(buf, out_buf.length + 4); + /* Reset the length and overwrite the header. */ + smb_setlen(buf, out_buf.length + 4); gss_release_buffer(&minor, &out_buf); return NT_STATUS_OK; @@ -440,9 +441,9 @@ 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. */ + * so ignore non-session messages. */ - if(CVAL(buf,0) == SMBkeepalive) { + if(CVAL(buf,0)) { return; } @@ -461,12 +462,12 @@ NTSTATUS cli_decrypt_message(struct cli_state *cli) NTSTATUS status; uint16 enc_ctx_num; - /* Ignore session keepalives. */ - if(CVAL(cli->inbuf,0) == SMBkeepalive) { + /* Ignore non-session messages. */ + if(CVAL(cli->inbuf,0)) { return NT_STATUS_OK; } - status = get_enc_ctx_num(cli->inbuf, &enc_ctx_num); + status = get_enc_ctx_num((const uint8_t *)cli->inbuf, &enc_ctx_num); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -484,8 +485,8 @@ NTSTATUS cli_decrypt_message(struct cli_state *cli) NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out) { - /* Ignore session keepalives. */ - if(CVAL(cli->outbuf,0) == SMBkeepalive) { + /* Ignore non-session messages. */ + if(CVAL(cli->outbuf,0)) { return NT_STATUS_OK; } diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c index d5cbe3b125..f03c21bd0e 100644 --- a/source3/libsmb/smb_signing.c +++ b/source3/libsmb/smb_signing.c @@ -745,8 +745,8 @@ bool srv_oplock_set_signing(bool onoff) bool srv_check_sign_mac(const char *inbuf, bool must_be_ok) { - /* Check if it's a session keepalive. */ - if(CVAL(inbuf,0) == SMBkeepalive) { + /* Check if it's a non-session message. */ + if(CVAL(inbuf,0)) { return True; } @@ -759,8 +759,8 @@ bool srv_check_sign_mac(const char *inbuf, bool must_be_ok) void srv_calculate_sign_mac(char *outbuf) { - /* Check if it's a session keepalive. */ - if(CVAL(outbuf,0) == SMBkeepalive) { + /* Check if it's a non-session message. */ + if(CVAL(outbuf,0)) { return; } diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 16e9372009..29166cf02e 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -6213,7 +6213,7 @@ uint32 lp_get_spoolss_state( void ) } /******************************************************************* - Ensure we don't use sendfile if server smb signing or selaing is active. + Ensure we don't use sendfile if server smb signing is active. ********************************************************************/ bool lp_use_sendfile(int snum) @@ -6224,8 +6224,7 @@ bool lp_use_sendfile(int snum) } return (_lp_use_sendfile(snum) && (get_remote_arch() != RA_WIN95) && - !srv_is_signing_active() && - !srv_encryption_on()); + !srv_is_signing_active()); } /******************************************************************* diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index f115fba91f..bae32e89f7 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -1867,7 +1867,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract goto err_exit; } - create_directory(conn, new_dir); + create_directory(conn, NULL, new_dir); /* For each driver file, archi\filexxx.yyy, if there is a duplicate file * listed for this driver which has already been moved, skip it (note: diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index a439c3a4f0..bc1761b0fd 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -236,7 +236,7 @@ bool schedule_aio_read_and_X(connection_struct *conn, } construct_reply_common((char *)req->inbuf, aio_ex->outbuf); - srv_set_message((const char *)req->inbuf, aio_ex->outbuf, 12, 0, True); + srv_set_message(aio_ex->outbuf, 12, 0, True); SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */ a = &aio_ex->acb; @@ -356,8 +356,9 @@ bool schedule_aio_write_and_X(connection_struct *conn, SSVAL(aio_ex->outbuf,smb_vwv2,numtowrite); SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1); show_msg(aio_ex->outbuf); - if (!send_smb(smbd_server_fd(),aio_ex->outbuf)) { - exit_server_cleanly("handle_aio_write: send_smb " + if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf, + IS_CONN_ENCRYPTED(fsp->conn))) { + exit_server_cleanly("handle_aio_write: srv_send_smb " "failed."); } DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write " @@ -387,7 +388,6 @@ 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); @@ -410,9 +410,9 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex) ret = errno; ERROR_NT(map_nt_error_from_unix(ret)); - outsize = srv_set_message(inbuf,outbuf,0,0,true); + outsize = srv_set_message(outbuf,0,0,true); } else { - outsize = srv_set_message(inbuf, outbuf,12,nread,False); + outsize = srv_set_message(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)); @@ -425,10 +425,11 @@ 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 " + if (!srv_send_smb(smbd_server_fd(),outbuf, + IS_CONN_ENCRYPTED(aio_ex->fsp->conn))) { + exit_server_cleanly("handle_aio_read_complete: srv_send_smb " "failed."); } @@ -497,7 +498,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) ret = errno; ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull); - srv_set_message(inbuf,outbuf,0,0,true); + srv_set_message(outbuf,0,0,true); } else { bool write_through = BITSETW(aio_ex->inbuf+smb_vwv7,0); NTSTATUS status; @@ -516,15 +517,15 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) ret = errno; ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull); - srv_set_message(inbuf,outbuf,0,0,true); + srv_set_message(outbuf,0,0,true); DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n", fsp->fsp_name, nt_errstr(status) )); } } show_msg(outbuf); - if (!send_smb(smbd_server_fd(),outbuf)) { - exit_server_cleanly("handle_aio_write: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn))) { + exit_server_cleanly("handle_aio_write: srv_send_smb failed."); } DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed " diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 0078bb7d13..c56f635dde 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -41,6 +41,7 @@ typedef struct _blocking_lock_record { enum brl_type lock_type; char *inbuf; int length; + bool encrypted; } blocking_lock_record; /* dlink list we store pending lock records on. */ @@ -149,7 +150,7 @@ static bool recalc_brl_timeout(void) ****************************************************************************/ bool push_blocking_lock_request( struct byte_range_lock *br_lck, - const char *inbuf, int length, + const struct smb_request *req, files_struct *fsp, int lock_timeout, int lock_num, @@ -161,6 +162,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, uint32 blocking_pid) { static bool set_lock_msg; + size_t length = smb_len(req->inbuf)+4; blocking_lock_record *blr; NTSTATUS status; @@ -188,7 +190,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, return False; } - blr->com_type = CVAL(inbuf,smb_com); + blr->com_type = CVAL(req->inbuf,smb_com); blr->fsp = fsp; if (lock_timeout == -1) { blr->expire_time.tv_sec = 0; @@ -204,8 +206,9 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, blr->lock_type = lock_type; blr->offset = offset; blr->count = count; - memcpy(blr->inbuf, inbuf, length); + memcpy(blr->inbuf, req->inbuf, length); blr->length = length; + blr->encrypted = req->encrypted; /* Add a pending lock record for this. */ status = brl_lock(smbd_messaging_context(), br_lck, @@ -242,7 +245,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, blr->fsp->fnum, blr->fsp->fsp_name )); /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); + srv_defer_sign_response(SVAL(req->inbuf,smb_mid)); return True; } @@ -259,7 +262,7 @@ static void reply_lockingX_success(blocking_lock_record *blr) smb_panic("Could not allocate smb_request"); } - init_smb_request(req, (uint8 *)blr->inbuf, 0); + init_smb_request(req, (uint8 *)blr->inbuf, 0, blr->encrypted); reply_outbuf(req, 2, 0); /* @@ -272,8 +275,10 @@ static void reply_lockingX_success(blocking_lock_record *blr) chain_reply(req); - if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) { - exit_server_cleanly("send_blocking_reply: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(blr->fsp->conn))) { + exit_server_cleanly("send_blocking_reply: srv_send_smb failed."); } } @@ -309,8 +314,9 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat } ERROR_NT(status); - if (!send_smb(smbd_server_fd(),outbuf)) { - exit_server_cleanly("generic_blocking_lock_error: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(),outbuf, + IS_CONN_ENCRYPTED(blr->fsp->conn))) { + exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed."); } } @@ -388,8 +394,10 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status */ SCVAL(outbuf,smb_com,SMBtrans2); ERROR_NT(status); - if (!send_smb(smbd_server_fd(),outbuf)) { - exit_server_cleanly("blocking_lock_reply_error: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + outbuf, + IS_CONN_ENCRYPTED(blr->fsp->conn))) { + exit_server_cleanly("blocking_lock_reply_error: srv_send_smb failed."); } break; } @@ -531,12 +539,12 @@ static bool process_trans2(blocking_lock_record *blr) return True; } - init_smb_request(req, (uint8 *)blr->inbuf, 0); + init_smb_request(req, (uint8 *)blr->inbuf, 0, blr->encrypted); SCVAL(req->inbuf, smb_com, SMBtrans2); SSVAL(params,0,0); /* Fake up max_data_bytes here - we know it fits. */ - send_trans2_replies(req, params, 2, NULL, 0, 0xffff); + send_trans2_replies(blr->fsp->conn, req, params, 2, NULL, 0, 0xffff); return True; } diff --git a/source3/smbd/error.c b/source3/smbd/error.c index c669e74146..de2de088ec 100644 --- a/source3/smbd/error.c +++ b/source3/smbd/error.c @@ -81,9 +81,9 @@ void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatu } } -int error_packet(const char *inbuf, char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file) +int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file) { - int outsize = srv_set_message(inbuf, outbuf,0,0,True); + int outsize = srv_set_message(outbuf,0,0,True); error_packet_set(outbuf, eclass, ecode, ntstatus, line, file); return outsize; } diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index f28016ccb3..a89f5cbbfe 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -30,7 +30,7 @@ extern int max_send; #define NERR_notsupported 50 -static void api_no_reply(struct smb_request *req); +static void api_no_reply(connection_struct *conn, struct smb_request *req); /******************************************************************* copies parameters and data, as needed, into the smb buffer @@ -81,7 +81,8 @@ static void copy_trans_params_and_data(char *outbuf, int align, Send a trans reply. ****************************************************************************/ -void send_trans_reply(struct smb_request *req, +void send_trans_reply(connection_struct *conn, + struct smb_request *req, char *rparam, int rparam_len, char *rdata, int rdata_len, bool buffer_too_large) @@ -129,8 +130,10 @@ void send_trans_reply(struct smb_request *req, } show_msg((char *)req->outbuf); - if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) - exit_server_cleanly("send_trans_reply: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) + exit_server_cleanly("send_trans_reply: srv_send_smb failed."); TALLOC_FREE(req->outbuf); @@ -175,8 +178,10 @@ void send_trans_reply(struct smb_request *req, } show_msg((char *)req->outbuf); - if (!send_smb(smbd_server_fd(), (char *)req->outbuf)) - exit_server_cleanly("send_trans_reply: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) + exit_server_cleanly("send_trans_reply: srv_send_smb failed."); tot_data_sent += this_ldata; tot_param_sent += this_lparam; @@ -188,7 +193,7 @@ void send_trans_reply(struct smb_request *req, Start the first part of an RPC reply which began with an SMBtrans request. ****************************************************************************/ -static void api_rpc_trans_reply(struct smb_request *req, smb_np_struct *p) +static void api_rpc_trans_reply(connection_struct *conn, struct smb_request *req, smb_np_struct *p) { bool is_data_outstanding; char *rdata = (char *)SMB_MALLOC(p->max_trans_reply); @@ -203,11 +208,11 @@ static void api_rpc_trans_reply(struct smb_request *req, smb_np_struct *p) if((data_len = read_from_pipe( p, rdata, p->max_trans_reply, &is_data_outstanding)) < 0) { SAFE_FREE(rdata); - api_no_reply(req); + api_no_reply(conn,req); return; } - send_trans_reply(req, NULL, 0, rdata, data_len, is_data_outstanding); + send_trans_reply(conn, req, NULL, 0, rdata, data_len, is_data_outstanding); SAFE_FREE(rdata); return; } @@ -216,7 +221,7 @@ static void api_rpc_trans_reply(struct smb_request *req, smb_np_struct *p) WaitNamedPipeHandleState ****************************************************************************/ -static void api_WNPHS(struct smb_request *req, smb_np_struct *p, +static void api_WNPHS(connection_struct *conn, struct smb_request *req, smb_np_struct *p, char *param, int param_len) { uint16 priority; @@ -231,10 +236,10 @@ static void api_WNPHS(struct smb_request *req, smb_np_struct *p, if (wait_rpc_pipe_hnd_state(p, priority)) { /* now send the reply */ - send_trans_reply(req, NULL, 0, NULL, 0, False); + send_trans_reply(conn, req, NULL, 0, NULL, 0, False); return; } - api_no_reply(req); + api_no_reply(conn,req); } @@ -242,7 +247,7 @@ static void api_WNPHS(struct smb_request *req, smb_np_struct *p, SetNamedPipeHandleState ****************************************************************************/ -static void api_SNPHS(struct smb_request *req, smb_np_struct *p, +static void api_SNPHS(connection_struct *conn, struct smb_request *req, smb_np_struct *p, char *param, int param_len) { uint16 id; @@ -257,10 +262,10 @@ static void api_SNPHS(struct smb_request *req, smb_np_struct *p, if (set_rpc_pipe_hnd_state(p, id)) { /* now send the reply */ - send_trans_reply(req, NULL, 0, NULL, 0, False); + send_trans_reply(conn, req, NULL, 0, NULL, 0, False); return; } - api_no_reply(req); + api_no_reply(conn,req); } @@ -268,7 +273,7 @@ static void api_SNPHS(struct smb_request *req, smb_np_struct *p, When no reply is generated, indicate unsupported. ****************************************************************************/ -static void api_no_reply(struct smb_request *req) +static void api_no_reply(connection_struct *conn, struct smb_request *req) { char rparam[4]; @@ -279,7 +284,7 @@ static void api_no_reply(struct smb_request *req) DEBUG(3,("Unsupported API fd command\n")); /* now send the reply */ - send_trans_reply(req, rparam, 4, NULL, 0, False); + send_trans_reply(conn, req, rparam, 4, NULL, 0, False); return; } @@ -321,7 +326,7 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid, /* Win9x does this call with a unicode pipe name, not a pnum. */ /* Just return success for now... */ DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n")); - send_trans_reply(req, NULL, 0, NULL, 0, False); + send_trans_reply(conn, req, NULL, 0, NULL, 0, False); return; } @@ -349,18 +354,18 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid, /* dce/rpc command */ reply = write_to_pipe(p, data, tdscnt); if (!reply) { - api_no_reply(req); + api_no_reply(conn, req); return; } - api_rpc_trans_reply(req, p); + api_rpc_trans_reply(conn, req, p); break; case TRANSACT_WAITNAMEDPIPEHANDLESTATE: /* Wait Named Pipe Handle state */ - api_WNPHS(req, p, params, tpscnt); + api_WNPHS(conn, req, p, params, tpscnt); break; case TRANSACT_SETNAMEDPIPEHANDLESTATE: /* Set Named Pipe Handle state */ - api_SNPHS(req, p, params, tpscnt); + api_SNPHS(conn, req, p, params, tpscnt); break; default: reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -472,8 +477,10 @@ static void handle_trans(connection_struct *conn, struct smb_request *req, state->max_data_return, state->max_param_return); - if (state->close_on_completion) + if (state->close_on_completion) { close_cnum(conn,state->vuid); + req->conn = NULL; + } return; } diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 3ab216c062..5a6df1f139 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -4605,7 +4605,7 @@ void api_reply(connection_struct *conn, uint16 vuid, /* If api_Unsupported returns false we can't return anything. */ if (reply) { - send_trans_reply(req, rparam, rparam_len, + send_trans_reply(conn, req, rparam, rparam_len, rdata, rdata_len, False); } diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index baab48f77e..7287210802 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -128,10 +128,10 @@ static bool notify_marshall_changes(int num_changes, Setup the common parts of the return packet and send it. *****************************************************************************/ -static void change_notify_reply_packet(const uint8 *request_buf, +static void change_notify_reply_packet(connection_struct *conn, + const uint8 *request_buf, NTSTATUS error_code) { - const char *inbuf = (const char *)request_buf; char outbuf[smb_size+38]; memset(outbuf, '\0', sizeof(outbuf)); @@ -143,15 +143,18 @@ 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. */ - srv_set_message((const char *)request_buf, outbuf,18,0,False); + srv_set_message(outbuf,18,0,False); show_msg(outbuf); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server_cleanly("change_notify_reply_packet: send_smb " + if (!srv_send_smb(smbd_server_fd(), + outbuf, + IS_CONN_ENCRYPTED(conn))) + exit_server_cleanly("change_notify_reply_packet: srv_send_smb " "failed."); } -void change_notify_reply(const uint8 *request_buf, uint32 max_param, +void change_notify_reply(connection_struct *conn, + const uint8 *request_buf, uint32 max_param, struct notify_change_buf *notify_buf) { prs_struct ps; @@ -159,7 +162,7 @@ void change_notify_reply(const uint8 *request_buf, uint32 max_param, uint8 tmp_request[smb_size]; if (notify_buf->num_changes == -1) { - change_notify_reply_packet(request_buf, NT_STATUS_OK); + change_notify_reply_packet(conn, request_buf, NT_STATUS_OK); notify_buf->num_changes = 0; return; } @@ -172,12 +175,12 @@ void change_notify_reply(const uint8 *request_buf, uint32 max_param, * We exceed what the client is willing to accept. Send * nothing. */ - change_notify_reply_packet(request_buf, NT_STATUS_OK); + change_notify_reply_packet(conn, request_buf, NT_STATUS_OK); goto done; } if (!(req = talloc(talloc_tos(), struct smb_request))) { - change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY); + change_notify_reply_packet(conn, request_buf, NT_STATUS_NO_MEMORY); goto done; } @@ -190,9 +193,9 @@ void change_notify_reply(const uint8 *request_buf, uint32 max_param, smb_setlen((char *)tmp_request, smb_size); SCVAL(tmp_request, smb_wct, 0); - init_smb_request(req, tmp_request,0); + init_smb_request(req, tmp_request,0, conn->encrypted_tid); - send_nt_replies(req, NT_STATUS_OK, prs_data_p(&ps), + send_nt_replies(conn, req, NT_STATUS_OK, prs_data_p(&ps), prs_offset(&ps), NULL, 0); done: @@ -243,9 +246,10 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, return status; } -NTSTATUS change_notify_add_request(const uint8 *inbuf, uint32 max_param, - uint32 filter, bool recursive, - struct files_struct *fsp) +NTSTATUS change_notify_add_request(const struct smb_request *req, + uint32 max_param, + uint32 filter, bool recursive, + struct files_struct *fsp) { struct notify_change_request *request = NULL; struct notify_mid_map *map = NULL; @@ -259,7 +263,7 @@ NTSTATUS change_notify_add_request(const uint8 *inbuf, uint32 max_param, request->mid_map = map; map->req = request; - memcpy(request->request_buf, inbuf, sizeof(request->request_buf)); + memcpy(request->request_buf, req->inbuf, sizeof(request->request_buf)); request->max_param = max_param; request->filter = filter; request->fsp = fsp; @@ -268,11 +272,11 @@ NTSTATUS change_notify_add_request(const uint8 *inbuf, uint32 max_param, DLIST_ADD_END(fsp->notify->requests, request, struct notify_change_request *); - map->mid = SVAL(inbuf, smb_mid); + map->mid = SVAL(req->inbuf, smb_mid); DLIST_ADD(notify_changes_by_mid, map); /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); + srv_defer_sign_response(SVAL(req->inbuf,smb_mid)); return NT_STATUS_OK; } @@ -325,7 +329,8 @@ void remove_pending_change_notify_requests_by_mid(uint16 mid) return; } - change_notify_reply_packet(map->req->request_buf, NT_STATUS_CANCELLED); + change_notify_reply_packet(map->req->fsp->conn, + map->req->request_buf, NT_STATUS_CANCELLED); change_notify_remove_request(map->req); } @@ -341,7 +346,7 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp, } while (fsp->notify->requests != NULL) { - change_notify_reply_packet( + change_notify_reply_packet(fsp->conn, fsp->notify->requests->request_buf, status); change_notify_remove_request(fsp->notify->requests); } @@ -435,7 +440,8 @@ static void notify_fsp(files_struct *fsp, uint32 action, const char *name) * TODO: do we have to walk the lists of requests pending? */ - change_notify_reply(fsp->notify->requests->request_buf, + change_notify_reply(fsp->conn, + fsp->notify->requests->request_buf, fsp->notify->requests->max_param, fsp->notify); diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 69772b6bec..8ac0217dcd 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -66,7 +66,8 @@ static char *nttrans_realloc(char **ptr, size_t size) HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, +void send_nt_replies(connection_struct *conn, + struct smb_request *req, NTSTATUS nt_error, char *params, int paramsize, char *pdata, int datasize) { @@ -242,8 +243,10 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, /* Send the packet */ show_msg((char *)req->outbuf); - if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) { - exit_server_cleanly("send_nt_replies: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) { + exit_server_cleanly("send_nt_replies: srv_send_smb failed."); } TALLOC_FREE(req->outbuf); @@ -726,7 +729,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn, DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); /* Send the required number of replies */ - send_nt_replies(req, NT_STATUS_OK, params, param_len, *ppdata, 0); + send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0); return; } @@ -1080,7 +1083,7 @@ static void call_nt_transact_create(connection_struct *conn, DEBUG(5,("call_nt_transact_create: open name = %s\n", fname)); /* Send the required number of replies */ - send_nt_replies(req, NT_STATUS_OK, params, param_len, *ppdata, 0); + send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0); return; } @@ -1474,7 +1477,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, * here. */ - change_notify_reply(req->inbuf, max_param_count, fsp->notify); + change_notify_reply(fsp->conn, req->inbuf, max_param_count, fsp->notify); /* * change_notify_reply() above has independently sent its @@ -1487,7 +1490,9 @@ static void call_nt_transact_notify_change(connection_struct *conn, * No changes pending, queue the request */ - status = change_notify_add_request(req->inbuf, max_param_count, filter, + status = change_notify_add_request(req, + max_param_count, + filter, recursive, fsp); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1554,7 +1559,7 @@ static void call_nt_transact_rename(connection_struct *conn, /* * Rename was successful. */ - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", fsp->fsp_name, new_name)); @@ -1657,7 +1662,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, SIVAL(params,0,(uint32)sd_size); if (max_data_count < sd_size) { - send_nt_replies(req, NT_STATUS_BUFFER_TOO_SMALL, + send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL, params, 4, *ppdata, 0); TALLOC_FREE(frame); return; @@ -1686,7 +1691,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, SMB_ASSERT(sd_size == blob.length); memcpy(data, blob.data, sd_size); - send_nt_replies(req, NT_STATUS_OK, params, 4, data, (int)sd_size); + send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size); TALLOC_FREE(frame); return; @@ -1744,7 +1749,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, } done: - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); return; } @@ -1793,7 +1798,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, so we can know if we need to pre-allocate or not */ DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum)); - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); return; case FSCTL_CREATE_OR_GET_OBJECT_ID: @@ -1819,7 +1824,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, push_file_id_16(pdata, &fsp->file_id); memcpy(pdata+16,create_volume_objectid(conn,objid),16); push_file_id_16(pdata+32, &fsp->file_id); - send_nt_replies(req, NT_STATUS_OK, NULL, 0, + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, pdata, data_count); return; } @@ -1964,7 +1969,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, talloc_destroy(shadow_data->mem_ctx); - send_nt_replies(req, NT_STATUS_OK, NULL, 0, + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, pdata, data_count); return; @@ -2020,7 +2025,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, */ /* this works for now... */ - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); return; } default: @@ -2306,7 +2311,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, break; } - send_nt_replies(req, nt_status, params, param_len, + send_nt_replies(conn, req, nt_status, params, param_len, pdata, data_len); } @@ -2436,7 +2441,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, return; } - send_nt_replies(req, NT_STATUS_OK, params, param_len, + send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, pdata, data_len); } #endif /* HAVE_SYS_QUOTAS */ diff --git a/source3/smbd/open.c b/source3/smbd/open.c index b6e6adde8a..e3fae02b83 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2267,7 +2267,7 @@ NTSTATUS open_directory(connection_struct *conn, return NT_STATUS_OK; } -NTSTATUS create_directory(connection_struct *conn, const char *directory) +NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory) { NTSTATUS status; SMB_STRUCT_STAT sbuf; @@ -2275,7 +2275,7 @@ NTSTATUS create_directory(connection_struct *conn, const char *directory) SET_STAT_INVALID(sbuf); - status = open_directory(conn, NULL, directory, &sbuf, + status = open_directory(conn, req, directory, &sbuf, FILE_READ_ATTRIBUTES, /* Just a stat open */ FILE_SHARE_NONE, /* Ignored for stat opens */ FILE_CREATE, diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 8a5b1f4ecd..277e07c178 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -252,13 +252,7 @@ static char *new_break_smb_message(TALLOC_CTX *mem_ctx, } memset(result,'\0',smb_size); - if (!srv_encryption_on()) { - cli_set_message(result,8,0,true); - } else { - char inbuf[8]; - smb_set_enclen(inbuf,4,srv_enc_ctx()); - srv_set_message(inbuf,result,8,0,true); - } + srv_set_message(result,8,0,true); SCVAL(result,smb_com,SMBlockingX); SSVAL(result,smb_tid,fsp->conn->cnum); SSVAL(result,smb_pid,0xFFFF); @@ -455,8 +449,10 @@ static void process_oplock_async_level2_break_message(struct messaging_context * sign_state = srv_oplock_set_signing(False); show_msg(break_msg); - if (!send_smb(smbd_server_fd(), break_msg)) { - exit_server_cleanly("oplock_break: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + break_msg, + IS_CONN_ENCRYPTED(fsp->conn))) { + exit_server_cleanly("oplock_break: srv_send_smb failed."); } /* Restore the sign state to what it was. */ @@ -560,8 +556,10 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, sign_state = srv_oplock_set_signing(False); show_msg(break_msg); - if (!send_smb(smbd_server_fd(), break_msg)) { - exit_server_cleanly("oplock_break: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + break_msg, + IS_CONN_ENCRYPTED(fsp->conn))) { + exit_server_cleanly("oplock_break: srv_send_smb failed."); } /* Restore the sign state to what it was. */ @@ -637,8 +635,10 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, sign_state = srv_oplock_set_signing(False); show_msg(break_msg); - if (!send_smb(smbd_server_fd(), break_msg)) { - exit_server_cleanly("oplock_break: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + break_msg, + IS_CONN_ENCRYPTED(fsp->conn))) { + exit_server_cleanly("oplock_break: srv_send_smb failed."); } /* Restore the sign state to what it was. */ diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index 88b67c03e5..6b4b83d97d 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -291,8 +291,7 @@ void reply_pipe_read_and_X(struct smb_request *req) return; } - srv_set_message((const char *)req->inbuf, - (char *)req->outbuf, 12, nread, False); + srv_set_message((char *)req->outbuf, 12, nread, False); SSVAL(req->outbuf,smb_vwv5,nread); SSVAL(req->outbuf,smb_vwv6,smb_offset(data,req->outbuf)); diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 48a6d18bc9..32d1d058e3 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -50,14 +50,52 @@ enum smb_read_errors *get_srv_read_error(void) return &smb_read_error; } +/**************************************************************************** + Send an smb to a fd. +****************************************************************************/ + +bool srv_send_smb(int fd, char *buffer, bool do_encrypt) +{ + size_t len; + size_t nwritten=0; + ssize_t ret; + char *buf_out = buffer; + + /* Sign the outgoing packet if required. */ + srv_calculate_sign_mac(buf_out); + + if (do_encrypt) { + 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,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; +} + /******************************************************************* 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 srv_set_message(char *buf, int num_words, int num_bytes, bool zero) @@ -67,22 +105,14 @@ int srv_set_message(const char *frombuf, } 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); - } + smb_setlen(buf,(smb_size + num_words*2 + num_bytes - 4)); return (smb_size + num_words*2 + num_bytes); } -static bool valid_smb_header(const char *inbuf) +static bool valid_smb_header(const uint8_t *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); + if (is_encrypted_packet(inbuf)) { + return true; } return (strncmp(smb_base(inbuf),"\377SMB",4) == 0); } @@ -162,7 +192,7 @@ static ssize_t read_packet_remainder(int fd, (2*14) + /* word count (including bcc) */ \ 1 /* pad byte */) -ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, +static ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, const char lenbuf[4], int fd, char **buffer, @@ -202,7 +232,7 @@ ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, * valid writeX call. */ - if (is_valid_writeX_buffer(writeX_header)) { + if (is_valid_writeX_buffer((uint8_t *)writeX_header)) { /* * If the data offset is beyond what * we've read, drain the extra bytes. @@ -310,7 +340,7 @@ static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, return -1; } - if (CVAL(lenbuf,0) != SMBkeepalive && + if (CVAL(lenbuf,0) == 0 && min_recv_size && smb_len_large(lenbuf) > min_recv_size && /* Could be a UNIX large writeX. */ !srv_is_signing_active()) { @@ -350,18 +380,24 @@ static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, return len + 4; } -ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, - unsigned int timeout, size_t *p_unread) +static ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, + int fd, + char **buffer, + unsigned int timeout, + size_t *p_unread, + bool *p_encrypted) { ssize_t len; + *p_encrypted = false; + len = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout, p_unread); if (len < 0) { return -1; } - if (srv_encryption_on()) { + if (is_encrypted_packet((uint8_t *)*buffer)) { NTSTATUS status = srv_decrypt_buffer(*buffer); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("receive_smb_talloc: SMB decryption failed on " @@ -371,6 +407,7 @@ ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, SMB_READ_BAD_DECRYPT); return -1; } + *p_encrypted = true; } /* Check the incoming SMB signature. */ @@ -390,7 +427,8 @@ ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, void init_smb_request(struct smb_request *req, const uint8 *inbuf, - size_t unread_bytes) + size_t unread_bytes, + bool encrypted) { size_t req_size = smb_len(inbuf) + 4; /* Ensure we have at least smb_size bytes. */ @@ -406,6 +444,8 @@ void init_smb_request(struct smb_request *req, req->tid = SVAL(inbuf, smb_tid); req->wct = CVAL(inbuf, smb_wct); req->unread_bytes = unread_bytes; + req->encrypted = encrypted; + req->conn = conn_find(req->tid); /* Ensure we have at least wct words and 2 bytes of bcc. */ if (smb_size + req->wct*2 > req_size) { @@ -463,6 +503,7 @@ static bool push_queued_message(struct smb_request *req, msg->request_time = request_time; msg->end_time = end_time; + msg->encrypted = req->encrypted; if (private_data) { msg->private_data = data_blob_talloc(msg, private_data, @@ -738,7 +779,8 @@ static bool receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer, size_t *buffer_len, int timeout, - size_t *p_unread) + size_t *p_unread, + bool *p_encrypted) { fd_set r_fds, w_fds; int selrtn; @@ -805,6 +847,7 @@ static bool receive_message_or_smb(TALLOC_CTX *mem_ctx, return False; } *buffer_len = msg->buf.length; + *p_encrypted = msg->encrypted; /* We leave this message on the queue so the open code can know this is a retry. */ @@ -921,7 +964,8 @@ static bool receive_message_or_smb(TALLOC_CTX *mem_ctx, goto again; } - len = receive_smb_talloc(mem_ctx, smbd_server_fd(), buffer, 0, p_unread); + len = receive_smb_talloc(mem_ctx, smbd_server_fd(), + buffer, 0, p_unread, p_encrypted); if (len == -1) { return False; @@ -1288,8 +1332,7 @@ void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes) } construct_reply_common((char *)req->inbuf, (char *)req->outbuf); - srv_set_message((const char *)req->inbuf, - (char *)req->outbuf, num_words, num_bytes, false); + srv_set_message((char *)req->outbuf, num_words, num_bytes, false); /* * Zero out the word area, the caller has to take care of the bcc area * himself @@ -1347,11 +1390,11 @@ static void smb_dump(const char *name, int type, const char *data, ssize_t len) find. ****************************************************************************/ -static void switch_message(uint8 type, struct smb_request *req, int size) +static connection_struct *switch_message(uint8 type, struct smb_request *req, int size) { int flags; uint16 session_tag; - connection_struct *conn; + connection_struct *conn = NULL; static uint16 last_session_tag = UID_FIELD_INVALID; @@ -1359,7 +1402,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 (!valid_smb_header((const char *)req->inbuf) + if (!valid_smb_header(req->inbuf) || (size < (smb_size - 4))) { DEBUG(2,("Non-SMB packet of length %d. Terminating server\n", smb_len(req->inbuf))); @@ -1370,7 +1413,7 @@ static void switch_message(uint8 type, struct smb_request *req, int size) DEBUG(0,("Unknown message type %d!\n",type)); smb_dump("Unknown", 1, (char *)req->inbuf, size); reply_unknown_new(req, type); - return; + return NULL; } flags = smb_messages[type].flags; @@ -1378,7 +1421,7 @@ static void switch_message(uint8 type, struct smb_request *req, int size) /* In share mode security we must ignore the vuid. */ session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : req->vuid; - conn = conn_find(req->tid); + conn = req->conn; DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n", smb_fn_name(type), (int)sys_getpid(), (unsigned long)conn)); @@ -1423,12 +1466,12 @@ static void switch_message(uint8 type, struct smb_request *req, int size) } else { reply_doserror(req, ERRSRV, ERRinvnid); } - return; + return NULL; } if (!change_to_user(conn,session_tag)) { reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid)); - return; + return conn; } /* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */ @@ -1436,13 +1479,13 @@ static void switch_message(uint8 type, struct smb_request *req, int size) /* Does it need write permission? */ if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) { reply_nterror(req, NT_STATUS_MEDIA_WRITE_PROTECTED); - return; + return conn; } /* IPC services are limited */ if (IS_IPC(conn) && !(flags & CAN_IPC)) { reply_doserror(req, ERRSRV,ERRaccess); - return; + return conn; } } else { /* This call needs to be run as root */ @@ -1451,21 +1494,24 @@ static void switch_message(uint8 type, struct smb_request *req, int size) /* load service specific parameters */ if (conn) { + if (req->encrypted) { + conn->encrypted_tid = true; + /* encrypted required from now on. */ + conn->encrypt_level = Required; + } else if (ENCRYPTION_REQUIRED(conn)) { + uint8 com = CVAL(req->inbuf,smb_com); + if (com != SMBtrans2 && com != SMBtranss2) { + exit_server_cleanly("encryption required " + "on connection"); + return conn; + } + } + if (!set_current_service(conn,SVAL(req->inbuf,smb_flg), (flags & (AS_USER|DO_CHDIR) ?True:False))) { reply_doserror(req, ERRSRV, ERRaccess); - return; - } - - if (conn->encrypt_level == Required && SVAL(req->inbuf,4) != 0x45FF ) { - /* An encrypted packet has 0xFF 'E' at offset 4 - * which is little endian 0x45FF */ - uint8 com = CVAL(req->inbuf,smb_com); - if (com != SMBtrans2 && com != SMBtranss2) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } + return conn; } conn->num_smb_operations++; } @@ -1476,19 +1522,21 @@ static void switch_message(uint8 type, struct smb_request *req, int size) !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) { reply_doserror(req, ERRSRV, ERRaccess); - return; + return conn; } smb_messages[type].fn_new(conn, req); + return req->conn; } /**************************************************************************** Construct a reply to the incoming packet. ****************************************************************************/ -static void construct_reply(char *inbuf, int size, size_t unread_bytes) +static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool encrypted) { uint8 type = CVAL(inbuf,smb_com); + connection_struct *conn; struct smb_request *req; chain_size = 0; @@ -1498,9 +1546,9 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes) if (!(req = talloc(talloc_tos(), struct smb_request))) { smb_panic("could not allocate smb_request"); } - init_smb_request(req, (uint8 *)inbuf, unread_bytes); + init_smb_request(req, (uint8 *)inbuf, unread_bytes, encrypted); - switch_message(type, req, size); + conn = switch_message(type, req, size); if (req->unread_bytes) { /* writeX failed. drain socket. */ @@ -1519,8 +1567,10 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes) show_msg((char *)req->outbuf); } - if (!send_smb(smbd_server_fd(), (char *)req->outbuf)) { - exit_server_cleanly("construct_reply: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn)||req->encrypted)) { + exit_server_cleanly("construct_reply: srv_send_smb failed."); } TALLOC_FREE(req); @@ -1532,7 +1582,7 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes) Process an smb from the client ****************************************************************************/ -static void process_smb(char *inbuf, size_t nread, size_t unread_bytes) +static void process_smb(char *inbuf, size_t nread, size_t unread_bytes, bool encrypted) { static int trans_num; int msg_type = CVAL(inbuf,0); @@ -1553,7 +1603,7 @@ static void process_smb(char *inbuf, size_t nread, size_t unread_bytes) static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81}; DEBUG( 1, ( "Connection denied from %s\n", client_addr(get_client_fd(),addr,sizeof(addr)) ) ); - (void)send_smb(smbd_server_fd(),(char *)buf); + (void)srv_send_smb(smbd_server_fd(),(char *)buf,false); exit_server_cleanly("connection denied"); } } @@ -1574,7 +1624,7 @@ static void process_smb(char *inbuf, size_t nread, size_t unread_bytes) show_msg(inbuf); - construct_reply(inbuf,nread,unread_bytes); + construct_reply(inbuf,nread,unread_bytes,encrypted); trans_num++; } @@ -1611,7 +1661,7 @@ void remove_from_common_flags2(uint32 v) void construct_reply_common(const char *inbuf, char *outbuf) { - srv_set_message(inbuf,outbuf,0,0,false); + srv_set_message(outbuf,0,0,false); SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); SIVAL(outbuf,smb_rcls,0); @@ -1734,7 +1784,7 @@ void chain_reply(struct smb_request *req) if (!(req2 = talloc(talloc_tos(), struct smb_request))) { smb_panic("could not allocate smb_request"); } - init_smb_request(req2, (uint8 *)inbuf2,0); + init_smb_request(req2, (uint8 *)inbuf2,0, req->encrypted); /* process the request */ switch_message(smb_com2, req2, new_size); @@ -2020,6 +2070,7 @@ void smbd_process(void) int num_echos; char *inbuf; size_t inbuf_len; + bool encrypted = false; TALLOC_CTX *frame = talloc_stackframe(); errno = 0; @@ -2035,7 +2086,9 @@ void smbd_process(void) run_events(smbd_event_context(), 0, NULL, NULL); while (!receive_message_or_smb(NULL, &inbuf, &inbuf_len, - select_timeout, &unread_bytes)) { + select_timeout, + &unread_bytes, + &encrypted)) { if(!timeout_processing(&select_timeout, &last_timeout_processing_time)) return; @@ -2054,7 +2107,7 @@ void smbd_process(void) */ num_echos = smb_echo_count; - process_smb(inbuf, inbuf_len, unread_bytes); + process_smb(inbuf, inbuf_len, unread_bytes, encrypted); TALLOC_FREE(inbuf); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index c859efd370..b6efccdb15 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -391,7 +391,7 @@ void reply_special(char *inbuf) /* * We only really use 4 bytes of the outbuf, but for the smb_setlen - * calculation & friends (send_smb uses that) we need the full smb + * calculation & friends (srv_send_smb uses that) we need the full smb * header. */ char outbuf[smb_size]; @@ -470,7 +470,7 @@ void reply_special(char *inbuf) DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n", msg_type, msg_flags)); - send_smb(smbd_server_fd(), outbuf); + srv_send_smb(smbd_server_fd(), outbuf, false); return; } @@ -523,6 +523,7 @@ void reply_tcon(connection_struct *conn, struct smb_request *req) password_blob = data_blob(password, pwlen+1); conn = make_connection(service,password_blob,dev,req->vuid,&nt_status); + req->conn = conn; data_blob_clear_free(&password_blob); @@ -578,6 +579,7 @@ void reply_tcon_and_X(connection_struct *conn, struct smb_request *req) /* we might have to close an old one */ if ((tcon_flags & 0x1) && conn) { close_cnum(conn,req->vuid); + req->conn = NULL; } if ((passlen > MAX_PASS_LEN) || (passlen >= smb_buflen(req->inbuf))) { @@ -646,6 +648,7 @@ void reply_tcon_and_X(connection_struct *conn, struct smb_request *req) conn = make_connection(service, password, client_devicetype, req->vuid, &nt_status); + req->conn =conn; data_blob_clear_free(&password); @@ -2725,7 +2728,7 @@ void reply_readbraw(connection_struct *conn, struct smb_request *req) START_PROFILE(SMBreadbraw); - if (srv_is_signing_active() || srv_encryption_on()) { + if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) { exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - " "raw reads/writes are disallowed."); } @@ -2951,8 +2954,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", return; } - srv_set_message((const char *)req->inbuf, - (char *)req->outbuf, 5, nread+3, False); + srv_set_message((char *)req->outbuf, 5, nread+3, False); SSVAL(req->outbuf,smb_vwv0,nread); SSVAL(req->outbuf,smb_vwv5,nread+3); @@ -3039,8 +3041,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", return; } - srv_set_message((const char *)req->inbuf, - (char *)req->outbuf, 5, nread+3, False); + srv_set_message((char *)req->outbuf, 5, nread+3, False); SSVAL(req->outbuf,smb_vwv0,nread); SSVAL(req->outbuf,smb_vwv5,nread+3); @@ -3058,12 +3059,12 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", Setup readX header. ****************************************************************************/ -static int setup_readX_header(const char *inbuf, char *outbuf, size_t smb_maxcnt) +static int setup_readX_header(char *outbuf, size_t smb_maxcnt) { int outsize; char *data; - outsize = srv_set_message(inbuf, outbuf,12,smb_maxcnt,False); + outsize = srv_set_message(outbuf,12,smb_maxcnt,False); data = smb_buf(outbuf); memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */ @@ -3113,6 +3114,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, */ if ((chain_size == 0) && (CVAL(req->inbuf,smb_vwv0) == 0xFF) && + !is_encrypted_packet(req->inbuf) && lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) { uint8 headerbuf[smb_size + 12 * 2]; DATA_BLOB header; @@ -3126,8 +3128,7 @@ 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((const char *)req->inbuf, - (char *)headerbuf, smb_maxcnt); + setup_readX_header((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. */ @@ -3178,8 +3179,7 @@ normal_read: uint8 headerbuf[smb_size + 2*12]; construct_reply_common((char *)req->inbuf, (char *)headerbuf); - setup_readX_header((const char *)req->inbuf, - (char *)headerbuf, smb_maxcnt); + setup_readX_header((char *)headerbuf, smb_maxcnt); /* Send out the header. */ if (write_data(smbd_server_fd(), (char *)headerbuf, @@ -3206,8 +3206,7 @@ normal_read: return; } - setup_readX_header((const char *)req->inbuf, - (char *)req->outbuf, nread); + setup_readX_header((char *)req->outbuf, nread); DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n", fsp->fnum, (int)smb_maxcnt, (int)nread ) ); @@ -3272,7 +3271,7 @@ void reply_read_and_X(connection_struct *conn, struct smb_request *req) return; } /* We currently don't do this on signed or sealed data. */ - if (srv_is_signing_active() || srv_encryption_on()) { + if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) { reply_nterror(req, NT_STATUS_NOT_SUPPORTED); END_PROFILE(SMBreadX); return; @@ -3463,13 +3462,15 @@ void reply_writebraw(connection_struct *conn, struct smb_request *req) * it to send more bytes */ memcpy(buf, req->inbuf, smb_size); - outsize = srv_set_message((const char *)req->inbuf, buf, + outsize = srv_set_message(buf, Protocol>PROTOCOL_COREPLUS?1:0,0,True); SCVAL(buf,smb_com,SMBwritebraw); SSVALS(buf,smb_vwv0,0xFFFF); show_msg(buf); - if (!send_smb(smbd_server_fd(),buf)) { - exit_server_cleanly("reply_writebraw: send_smb " + if (!srv_send_smb(smbd_server_fd(), + buf, + IS_CONN_ENCRYPTED(conn))) { + exit_server_cleanly("reply_writebraw: srv_send_smb " "failed."); } @@ -3788,14 +3789,14 @@ void reply_write(connection_struct *conn, struct smb_request *req) (2*14) + /* word count (including bcc) */ \ 1 /* pad byte */) -bool is_valid_writeX_buffer(const char *inbuf) +bool is_valid_writeX_buffer(const uint8_t *inbuf) { size_t numtowrite; connection_struct *conn = NULL; unsigned int doff = 0; size_t len = smb_len_large(inbuf); - if (srv_encryption_on()) { + if (is_encrypted_packet(inbuf)) { /* Can't do this on encrypted * connections. */ return false; @@ -4476,6 +4477,7 @@ void reply_tdis(connection_struct *conn, struct smb_request *req) conn->used = False; close_cnum(conn,req->vuid); + req->conn = NULL; reply_outbuf(req, 0, 0); END_PROFILE(SMBtdis); @@ -4526,8 +4528,10 @@ void reply_echo(connection_struct *conn, struct smb_request *req) SSVAL(req->outbuf,smb_vwv0,seq_num); show_msg((char *)req->outbuf); - if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) - exit_server_cleanly("reply_echo: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn)||req->encrypted)) + exit_server_cleanly("reply_echo: srv_send_smb failed."); } DEBUG(3,("echo %d times\n", smb_reverb)); @@ -4830,7 +4834,7 @@ void reply_mkdir(connection_struct *conn, struct smb_request *req) return; } - status = create_directory(conn, directory); + status = create_directory(conn, req, directory); DEBUG(5, ("create_directory returned %s\n", nt_errstr(status))); @@ -6803,8 +6807,7 @@ void reply_lockingX(connection_struct *conn, struct smb_request *req) * onto the blocking lock queue. */ if(push_blocking_lock_request(br_lck, - (char *)req->inbuf, - smb_len(req->inbuf)+4, + req, fsp, lock_timeout, i, diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c index 24ecb77fd5..21fca73fea 100644 --- a/source3/smbd/seal.c +++ b/source3/smbd/seal.c @@ -36,24 +36,37 @@ 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 ? + Return global enc context - this must change if we ever do multiple contexts. ******************************************************************************/ -bool srv_encryption_on(void) +uint16_t srv_enc_ctx(void) { - if (srv_trans_enc_ctx) { - return common_encryption_on(srv_trans_enc_ctx->es); - } - return false; + return srv_trans_enc_ctx->es->enc_ctx_num; } /****************************************************************************** - Return global enc context - this must change if we ever do multiple contexts. + Is this an incoming encrypted packet ? ******************************************************************************/ -uint16 srv_enc_ctx(void) +bool is_encrypted_packet(const uint8_t *inbuf) { - return srv_trans_enc_ctx->es->enc_ctx_num; + NTSTATUS status; + uint16_t enc_num; + + /* Ignore non-session messages. */ + if(CVAL(inbuf,0)) { + return false; + } + + status = get_enc_ctx_num(inbuf, &enc_num); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + if (srv_trans_enc_ctx && enc_num == srv_enc_ctx()) { + return true; + } + return false; } /****************************************************************************** @@ -292,9 +305,9 @@ 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. */ + * so ignore non-session messages. */ - if(CVAL(buf,0) == SMBkeepalive) { + if(CVAL(buf,0)) { return; } @@ -309,8 +322,8 @@ void srv_free_enc_buffer(char *buf) NTSTATUS srv_decrypt_buffer(char *buf) { - /* Ignore session keepalives. */ - if(CVAL(buf,0) == SMBkeepalive) { + /* Ignore non-session messages. */ + if(CVAL(buf,0)) { return NT_STATUS_OK; } @@ -329,8 +342,8 @@ NTSTATUS srv_encrypt_buffer(char *buf, char **buf_out) { *buf_out = buf; - /* Ignore session keepalives. */ - if(CVAL(buf,0) == SMBkeepalive) { + /* Ignore non-session messages. */ + if(CVAL(buf,0)) { return NT_STATUS_OK; } @@ -698,6 +711,7 @@ NTSTATUS srv_encryption_start(connection_struct *conn) srv_trans_enc_ctx->es->enc_on = true; partial_srv_trans_enc_ctx = NULL; + return NT_STATUS_OK; } diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 8ca012ff24..e44a540554 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -139,7 +139,7 @@ static void reply_sesssetup_blob(connection_struct *conn, } show_msg((char *)req->outbuf); - send_smb(smbd_server_fd(),(char *)req->outbuf); + srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted); TALLOC_FREE(req->outbuf); } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index eba8cb50f0..1e421a70b6 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -575,7 +575,8 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list * HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -void send_trans2_replies(struct smb_request *req, +void send_trans2_replies(connection_struct *conn, + struct smb_request *req, const char *params, int paramsize, const char *pdata, @@ -737,8 +738,10 @@ void send_trans2_replies(struct smb_request *req, /* Send the packet */ show_msg((char *)req->outbuf); - if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) - exit_server_cleanly("send_trans2_replies: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) + exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); TALLOC_FREE(req->outbuf); @@ -956,7 +959,7 @@ static void call_trans2open(connection_struct *conn, } /* Send the required number of replies */ - send_trans2_replies(req, params, 30, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes); } /********************************************************* @@ -2026,7 +2029,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd SSVAL(params,6,0); /* Never an EA error */ SSVAL(params,8,last_entry_off); - send_trans2_replies(req, params, 10, pdata, PTR_DIFF(p,pdata), + send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes); if ((! *directory) && dptr_path(dptr_num)) { @@ -2350,7 +2353,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd SSVAL(params,4,0); /* Never an EA error */ SSVAL(params,6,last_entry_off); - send_trans2_replies(req, params, 8, pdata, PTR_DIFF(p,pdata), + send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata), max_data_bytes); return; @@ -2389,13 +2392,23 @@ static void call_trans2qfsinfo(connection_struct *conn, info_level = SVAL(params,0); - if (IS_IPC(conn) || - (conn->encrypt_level == Required && SVAL(req->inbuf,4) != 0x45FF )) { + if (IS_IPC(conn)) { + if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { + DEBUG(0,("call_trans2qfsinfo: not an allowed " + "info level (0x%x) on IPC$.\n", + (unsigned int)info_level)); + reply_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + } + + if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { DEBUG(0,("call_trans2qfsinfo: encryption required " "and info level 0x%x sent.\n", (unsigned int)info_level)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + exit_server_cleanly("encryption required " + "on connection"); return; } } @@ -2906,7 +2919,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } - send_trans2_replies(req, params, 0, pdata, data_len, + send_trans2_replies(conn, req, params, 0, pdata, data_len, max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", @@ -2952,12 +2965,13 @@ static void call_trans2setfsinfo(connection_struct *conn, } } - if (conn->encrypt_level == Required && SVAL(req->inbuf,4) != 0x45FF ) { + if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) { DEBUG(0,("call_trans2setfsinfo: encryption required " "and info level 0x%x sent.\n", (unsigned int)info_level)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + exit_server_cleanly("encryption required " + "on connection"); return; } } @@ -3048,7 +3062,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", return; } - send_trans2_replies(req, + send_trans2_replies(conn, req, *pparams, param_len, *ppdata, @@ -3524,7 +3538,7 @@ static void call_trans2qpipeinfo(connection_struct *conn, return; } - send_trans2_replies(req, params, param_size, *ppdata, data_size, + send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, max_data_bytes); return; @@ -4456,7 +4470,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd return; } - send_trans2_replies(req, params, param_size, *ppdata, data_size, + send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, max_data_bytes); return; @@ -5160,8 +5174,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, ****************************************************************************/ static NTSTATUS smb_set_posix_lock(connection_struct *conn, - const uint8 *inbuf, - int length, + const struct smb_request *req, const char *pdata, int total_data, files_struct *fsp) @@ -5171,6 +5184,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, uint32 lock_pid; bool blocking_lock = False; enum brl_type lock_type; + NTSTATUS status = NT_STATUS_OK; if (fsp == NULL || fsp->fh->fd == -1) { @@ -5258,7 +5272,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, * onto the blocking lock queue. */ if(push_blocking_lock_request(br_lck, - (char *)inbuf, length, + req, fsp, -1, /* infinite timeout. */ 0, @@ -6316,7 +6330,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); SSVAL(params,0,0); - send_trans2_replies(req, params, 2, + send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes); return; @@ -6606,8 +6620,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; } - status = smb_set_posix_lock(conn, req->inbuf, - smb_len(req->inbuf) + 4, + status = smb_set_posix_lock(conn, req, pdata, total_data, fsp); break; } @@ -6675,7 +6688,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } SSVAL(params,0,0); - send_trans2_replies(req, params, 2, *ppdata, data_return_size, + send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size, max_data_bytes); return; @@ -6767,7 +6780,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, return; } - status = create_directory(conn, directory); + status = create_directory(conn, req, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -6793,7 +6806,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, SSVAL(params,0,0); - send_trans2_replies(req, params, 2, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes); return; } @@ -6847,7 +6860,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn, if(fnf_handle == 0) fnf_handle = 257; - send_trans2_replies(req, params, 6, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes); return; } @@ -6878,7 +6891,7 @@ static void call_trans2findnotifynext(connection_struct *conn, SSVAL(params,0,0); /* No changes */ SSVAL(params,2,0); /* No EA errors */ - send_trans2_replies(req, params, 4, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes); return; } @@ -6928,7 +6941,7 @@ static void call_trans2getdfsreferral(connection_struct *conn, SSVAL(req->inbuf, smb_flg2, SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); - send_trans2_replies(req,0,0,*ppdata,reply_size, max_data_bytes); + send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes); return; } @@ -6975,7 +6988,7 @@ static void call_trans2ioctl(connection_struct *conn, srvstr_push(pdata, req->flags2, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ - send_trans2_replies(req, *pparams, 0, *ppdata, 32, + send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32, max_data_bytes); return; } diff --git a/source3/utils/smbfilter.c b/source3/utils/smbfilter.c index 912d575c60..fb01e7f9a1 100644 --- a/source3/utils/smbfilter.c +++ b/source3/utils/smbfilter.c @@ -114,6 +114,30 @@ static void filter_request(char *buf) } +/**************************************************************************** + Send an smb to a fd. +****************************************************************************/ + +static bool send_smb(int fd, char *buffer) +{ + size_t len; + size_t nwritten=0; + ssize_t ret; + + len = smb_len(buffer) + 4; + + while (nwritten < len) { + ret = write_data(fd,buffer+nwritten,len - nwritten); + if (ret <= 0) { + DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n", + (int)len,(int)ret, strerror(errno) )); + return false; + } + nwritten += ret; + } + + return true; +} static void filter_child(int c, struct sockaddr_storage *dest_ss) { @@ -145,7 +169,7 @@ static void filter_child(int c, struct sockaddr_storage *dest_ss) if (num <= 0) continue; if (c != -1 && FD_ISSET(c, &fds)) { - if (!receive_smb(c, packet, 0, NULL)) { + if (!receive_smb_raw(c, packet, 0, NULL)) { d_printf("client closed connection\n"); exit(0); } @@ -156,7 +180,7 @@ static void filter_child(int c, struct sockaddr_storage *dest_ss) } } if (s != -1 && FD_ISSET(s, &fds)) { - if (!receive_smb(s, packet, 0, NULL)) { + if (!receive_smb_raw(s, packet, 0, NULL)) { d_printf("server closed connection\n"); exit(0); } -- cgit