#include "includes.h"
-extern struct auth_context *negprot_global_auth_context;
extern int smb_echo_count;
-extern int smb_read_error;
-
-const int total_buffer_size = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
/*
* Size of data we can send to client. Set
*/
int max_recv = BUFFER_SIZE;
-extern int last_message;
-extern int smb_read_error;
SIG_ATOMIC_T reload_after_sighup = 0;
SIG_ATOMIC_T got_sig_term = 0;
extern bool global_machine_password_needs_changing;
extern int max_send;
-/* Socket functions for smbd packet processing. */
+/* Accessor function for smb_read_error for smbd functions. */
+
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
-static bool valid_packet_size(len)
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
{
- /*
- * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
- * of header. Don't print the error if this fits.... JRA.
- */
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+ char *buf_out = buffer;
- if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
- DEBUG(0,("Invalid packet length! (%lu bytes).\n",
- (unsigned long)len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
+ /* Sign the outgoing packet if required. */
+ srv_calculate_sign_mac(buf_out);
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
+ 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;
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
+ 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;
}
-static ssize_t read_packet_remainder(int fd,
- char *buffer,
- unsigned int timeout,
- ssize_t len)
+/*******************************************************************
+ Setup the word count and byte count for a smb message.
+********************************************************************/
+
+int srv_set_message(char *buf,
+ int num_words,
+ int num_bytes,
+ bool zero)
{
- ssize_t ret;
+ 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);
+}
- if(len <= 0) {
- return len;
+static bool valid_smb_header(const uint8_t *inbuf)
+{
+ if (is_encrypted_packet(inbuf)) {
+ return true;
}
+ return (strncmp(smb_base(inbuf),"\377SMB",4) == 0);
+}
- if (timeout > 0) {
- ret = read_socket_with_timeout(fd,
- buffer,
- len,
- len,
- timeout);
- } else {
- ret = read_data(fd, buffer, len);
+/* Socket functions for smbd packet processing. */
+
+static bool valid_packet_size(size_t len)
+{
+ /*
+ * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
+ * of header. Don't print the error if this fits.... JRA.
+ */
+
+ if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ DEBUG(0,("Invalid packet length! (%lu bytes).\n",
+ (unsigned long)len));
+ return false;
}
+ return true;
+}
- if (ret != len) {
- if (smb_read_error == 0) {
- smb_read_error = READ_ERROR;
- }
- return -1;
+static NTSTATUS read_packet_remainder(int fd, char *buffer,
+ unsigned int timeout, ssize_t len)
+{
+ if (len <= 0) {
+ return NT_STATUS_OK;
}
- return len;
+ return read_socket_with_timeout(fd, buffer, len, len, timeout, NULL);
}
/****************************************************************************
(2*14) + /* word count (including bcc) */ \
1 /* pad byte */)
-ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
- const char lenbuf[4],
- int fd,
- char **buffer,
- unsigned int timeout,
- size_t *p_unread)
+static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
+ const char lenbuf[4],
+ int fd, char **buffer,
+ unsigned int timeout,
+ size_t *p_unread,
+ size_t *len_ret)
{
/* Size of a WRITEX call (+4 byte len). */
char writeX_header[4 + STANDARD_WRITE_AND_X_HEADER_SIZE];
ssize_t len = smb_len_large(lenbuf); /* Could be a UNIX large writeX. */
ssize_t toread;
- ssize_t ret;
+ NTSTATUS status;
- memcpy(writeX_header, lenbuf, sizeof(lenbuf));
+ memcpy(writeX_header, lenbuf, 4);
- if (timeout > 0) {
- ret = read_socket_with_timeout(fd,
- writeX_header + 4,
- STANDARD_WRITE_AND_X_HEADER_SIZE,
- STANDARD_WRITE_AND_X_HEADER_SIZE,
- timeout);
- } else {
- ret = read_data(fd,
- writeX_header+4,
- STANDARD_WRITE_AND_X_HEADER_SIZE);
- }
+ status = read_socket_with_timeout(
+ fd, writeX_header + 4,
+ STANDARD_WRITE_AND_X_HEADER_SIZE,
+ STANDARD_WRITE_AND_X_HEADER_SIZE,
+ timeout, NULL);
- if (ret != STANDARD_WRITE_AND_X_HEADER_SIZE) {
- if (smb_read_error == 0) {
- smb_read_error = READ_ERROR;
- }
- return -1;
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
/*
* 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.
/* Copy the header we've written. */
- *buffer = TALLOC_MEMDUP(mem_ctx,
+ *buffer = (char *)TALLOC_MEMDUP(mem_ctx,
writeX_header,
sizeof(writeX_header));
if (*buffer == NULL) {
DEBUG(0, ("Could not allocate inbuf of length %d\n",
(int)sizeof(writeX_header)));
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
+ return NT_STATUS_NO_MEMORY;
}
/* Work out the remaining bytes. */
*p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
-
- return newlen + 4;
+ *len_ret = newlen + 4;
+ return NT_STATUS_OK;
}
if (!valid_packet_size(len)) {
- return -1;
+ return NT_STATUS_INVALID_PARAMETER;
}
/*
if (*buffer == NULL) {
DEBUG(0, ("Could not allocate inbuf of length %d\n",
(int)len+4));
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
+ return NT_STATUS_NO_MEMORY;
}
/* Copy in what we already read. */
toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
if(toread > 0) {
- ret = read_packet_remainder(fd,
- (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
- timeout,
- toread);
- if (ret != toread) {
- return -1;
+ status = read_packet_remainder(
+ fd, (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
+ timeout, toread);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("receive_smb_raw_talloc_partial_read: %s\n",
+ nt_errstr(status)));
+ return status;
}
}
- return len + 4;
+ *len_ret = len + 4;
+ return NT_STATUS_OK;
}
-static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
- int fd,
- char **buffer,
- unsigned int timeout,
- size_t *p_unread)
+static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd,
+ char **buffer, unsigned int timeout,
+ size_t *p_unread, size_t *plen)
{
char lenbuf[4];
- ssize_t len,ret;
+ size_t len;
int min_recv_size = lp_min_receive_file_size();
+ NTSTATUS status;
- smb_read_error = 0;
*p_unread = 0;
- len = read_smb_length_return_keepalive(fd, lenbuf, timeout);
- if (len < 0) {
- DEBUG(10,("receive_smb_raw: length < 0!\n"));
-
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
-
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
+ status = read_smb_length_return_keepalive(fd, lenbuf, timeout, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("receive_smb_raw: %s\n", nt_errstr(status)));
+ return status;
}
- if (CVAL(lenbuf,0) != SMBkeepalive &&
+ if (CVAL(lenbuf,0) == 0 &&
min_recv_size &&
- len > min_recv_size &&
+ smb_len_large(lenbuf) > (min_recv_size + STANDARD_WRITE_AND_X_HEADER_SIZE) && /* Could be a UNIX large writeX. */
!srv_is_signing_active()) {
- return receive_smb_raw_talloc_partial_read(mem_ctx,
- lenbuf,
- fd,
- buffer,
- timeout,
- p_unread);
+ return receive_smb_raw_talloc_partial_read(
+ mem_ctx, lenbuf, fd, buffer, timeout, p_unread, plen);
}
if (!valid_packet_size(len)) {
- return -1;
+ return NT_STATUS_INVALID_PARAMETER;
}
/*
if (*buffer == NULL) {
DEBUG(0, ("Could not allocate inbuf of length %d\n",
(int)len+4));
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
+ return NT_STATUS_NO_MEMORY;
}
memcpy(*buffer, lenbuf, sizeof(lenbuf));
- ret = read_packet_remainder(fd, (*buffer)+4, timeout, len);
- if (ret != len) {
- return -1;
+ status = read_packet_remainder(fd, (*buffer)+4, timeout, len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- return len + 4;
+ *plen = len + 4;
+ return NT_STATUS_OK;
}
-ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer,
- unsigned int timeout, size_t *p_unread)
+static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd,
+ char **buffer, unsigned int timeout,
+ size_t *p_unread, bool *p_encrypted,
+ size_t *p_len)
{
- ssize_t len;
+ size_t len = 0;
+ NTSTATUS status;
+
+ *p_encrypted = false;
- len = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout, p_unread);
+ status = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout,
+ p_unread, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- if (len < 0) {
- return -1;
+ if (is_encrypted_packet((uint8_t *)*buffer)) {
+ 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) ));
+ return status;
+ }
+ *p_encrypted = true;
}
/* Check the incoming SMB signature. */
if (!srv_check_sign_mac(*buffer, true)) {
DEBUG(0, ("receive_smb: SMB Signature verification failed on "
"incoming packet!\n"));
- if (smb_read_error == 0) {
- smb_read_error = READ_BAD_SIG;
- }
- return -1;
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
- return len;
+ *p_len = len;
+ return NT_STATUS_OK;
}
/*
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. */
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) {
msg->request_time = request_time;
msg->end_time = end_time;
+ msg->encrypted = req->encrypted;
+ msg->processed = false;
if (private_data) {
msg->private_data = data_blob_talloc(msg, private_data,
DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
(unsigned int)msg_mid ));
if (mid == msg_mid) {
+
+ if (pml->processed) {
+ /* A processed message should not be
+ * rescheduled. */
+ DEBUG(0,("schedule_deferred_open_smb_message: LOGIC ERROR "
+ "message mid %u was already processed\n",
+ (unsigned int)msg_mid ));
+ continue;
+ }
+
DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
mid ));
pml->end_time.tv_sec = 0;
}
/****************************************************************************
- Return true if this mid is on the deferred queue.
+ Return true if this mid is on the deferred queue and was not yet processed.
****************************************************************************/
bool open_was_deferred(uint16 mid)
struct pending_message_list *pml;
for (pml = deferred_open_queue; pml; pml = pml->next) {
- if (SVAL(pml->buf.data,smb_mid) == mid) {
+ if (SVAL(pml->buf.data,smb_mid) == mid && !pml->processed) {
return True;
}
}
The timeout is in milliseconds
****************************************************************************/
-static bool receive_message_or_smb(TALLOC_CTX *mem_ctx,
- char **buffer,
- size_t *buffer_len,
- int timeout,
- size_t *p_unread)
+static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
+ size_t *buffer_len, int timeout,
+ size_t *p_unread, bool *p_encrypted)
{
fd_set r_fds, w_fds;
int selrtn;
struct timeval to;
int maxfd = 0;
- ssize_t len;
+ size_t len = 0;
+ NTSTATUS status;
*p_unread = 0;
- smb_read_error = 0;
again:
msg->buf.length);
if (*buffer == NULL) {
DEBUG(0, ("talloc failed\n"));
- smb_read_error = READ_ERROR;
- return False;
+ return NT_STATUS_NO_MEMORY;
}
*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. */
DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
- return True;
+
+ /* Mark the message as processed so this is not
+ * re-processed in error. */
+ msg->processed = true;
+ return NT_STATUS_OK;
}
}
/* Check if error */
if (selrtn == -1) {
/* something is wrong. Maybe the socket is dead? */
- smb_read_error = READ_ERROR;
- return False;
- }
-
+ return map_nt_error_from_unix(errno);
+ }
+
/* Did we timeout ? */
if (selrtn == 0) {
- smb_read_error = READ_TIMEOUT;
- return False;
+ return NT_STATUS_IO_TIMEOUT;
}
/*
goto again;
}
- len = receive_smb_talloc(mem_ctx, smbd_server_fd(), buffer, 0, p_unread);
+ /*
+ * We've just woken up from a protentially long select sleep.
+ * Ensure we process local messages as we need to synchronously
+ * process any messages from other smbd's to avoid file rename race
+ * conditions. This call is cheap if there are no messages waiting.
+ * JRA.
+ */
+ message_dispatch(smbd_messaging_context());
- if (len == -1) {
- return False;
+ status = receive_smb_talloc(mem_ctx, smbd_server_fd(), buffer, 0,
+ p_unread, p_encrypted, &len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- *buffer_len = (size_t)len;
+ *buffer_len = len;
- return True;
+ return NT_STATUS_OK;
}
/*
*/
static const struct smb_message_struct {
const char *name;
- void (*fn_new)(connection_struct *conn, struct smb_request *req);
+ void (*fn_new)(struct smb_request *req);
int flags;
} smb_messages[256] = {
/* 0x30 */ { NULL, NULL, 0 },
/* 0x31 */ { NULL, NULL, 0 },
/* 0x32 */ { "SMBtrans2",reply_trans2, AS_USER | CAN_IPC },
-/* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER},
+/* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER | CAN_IPC},
/* 0x34 */ { "SMBfindclose",reply_findclose,AS_USER},
/* 0x35 */ { "SMBfindnclose",reply_findnclose,AS_USER},
/* 0x36 */ { NULL, NULL, 0 },
if ((num_bytes > 0xffffff)
|| ((num_bytes + smb_size + num_words*2) > 0xffffff)) {
char *msg;
- asprintf(&msg, "num_bytes too large: %u",
- (unsigned)num_bytes);
+ if (asprintf(&msg, "num_bytes too large: %u",
+ (unsigned)num_bytes) == -1) {
+ msg = CONST_DISCARD(char *, "num_bytes too large");
+ }
smb_panic(msg);
}
}
construct_reply_common((char *)req->inbuf, (char *)req->outbuf);
- set_message((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
static void smb_dump(const char *name, int type, const char *data, ssize_t len)
{
int fd, i;
- pstring fname;
- if (DEBUGLEVEL < 50) return;
+ char *fname = NULL;
+ if (DEBUGLEVEL < 50) {
+ return;
+ }
if (len < 4) len = smb_len(data)+4;
for (i=1;i<100;i++) {
- slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
- type ? "req" : "resp");
+ if (asprintf(&fname, "/tmp/%s.%d.%s", name, i,
+ type ? "req" : "resp") == -1) {
+ return;
+ }
fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
if (fd != -1 || errno != EEXIST) break;
}
close(fd);
DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
}
+ SAFE_FREE(fname);
}
/****************************************************************************
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;
errno = 0;
- last_message = type;
-
/* 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(req->inbuf)
|| (size < (smb_size - 4))) {
DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
smb_len(req->inbuf)));
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;
/* 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));
} 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. */
/* 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 */
/* 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;
+ return conn;
}
conn->num_smb_operations++;
}
!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);
+ smb_messages[type].fn_new(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)
{
+ struct pending_message_list *pml = NULL;
uint8 type = CVAL(inbuf,smb_com);
+ connection_struct *conn;
struct smb_request *req;
chain_size = 0;
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);
+
+ conn = switch_message(type, req, size);
- switch_message(type, req, size);
+ /* If this was a deferred message and it's still there and
+ * was processed, remove it. */
+ pml = get_open_deferred_message(req->mid);
+ if (pml && pml->processed) {
+ remove_deferred_open_smb_message(req->mid);
+ }
if (req->unread_bytes) {
/* writeX failed. drain socket. */
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);
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);
DO_PROFILE_INC(smb_count);
if (trans_num == 0) {
+ char addr[INET6_ADDRSTRLEN];
+
/* on the first packet, check the global hosts allow/ hosts
deny parameters before doing any parsing of the packet
passed to us by the client. This prevents attacks on our
parsing code from hosts not in the hosts allow list */
+
if (!check_access(smbd_server_fd(), lp_hostsallow(-1),
lp_hostsdeny(-1))) {
/* send a negative session response "not listening on calling name" */
static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
- DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );
- (void)send_smb(smbd_server_fd(),(char *)buf);
+ DEBUG( 1, ( "Connection denied from %s\n",
+ client_addr(get_client_fd(),addr,sizeof(addr)) ) );
+ (void)srv_send_smb(smbd_server_fd(),(char *)buf,false);
exit_server_cleanly("connection denied");
}
}
show_msg(inbuf);
- construct_reply(inbuf,nread,unread_bytes);
+ construct_reply(inbuf,nread,unread_bytes,encrypted);
trans_num++;
}
void construct_reply_common(const char *inbuf, char *outbuf)
{
- set_message(outbuf,0,0,False);
+ srv_set_message(outbuf,0,0,false);
SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
SIVAL(outbuf,smb_rcls,0);
char *outbuf = (char *)req->outbuf;
size_t outsize = smb_len(outbuf) + 4;
size_t outsize_padded;
+ size_t padding;
size_t ofs, to_move;
struct smb_request *req2;
*/
outsize_padded = (outsize + 3) & ~3;
+ padding = outsize_padded - outsize;
/*
* remember how much the caller added to the chain, only counting
* stuff after the parameter words
*/
- chain_size += outsize_padded - smb_wct;
+ chain_size += (outsize_padded - smb_wct);
/*
* work out pointers into the original packets. The
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);
SCVAL(outbuf, smb_vwv0, smb_com2);
SSVAL(outbuf, smb_vwv1, chain_size + smb_wct - 4);
- if (outsize_padded > outsize) {
+ if (padding != 0) {
/*
* Due to padding we have some uninitialized bytes after the
* caller's output
*/
- memset(outbuf + outsize, 0, outsize_padded - outsize);
+ memset(outbuf + outsize, 0, padding);
}
- smb_setlen(outbuf, outsize2 + chain_size - 4);
+ smb_setlen(outbuf, outsize2 + caller_outputlen + padding - 4);
/*
* restore the saved data, being careful not to overwrite any data
SAFE_FREE(caller_output);
TALLOC_FREE(req2);
+ /*
+ * Reset the chain_size for our caller's offset calculations
+ */
+
+ chain_size -= (outsize_padded - smb_wct);
+
return;
}
Process any timeout housekeeping. Return False if the caller should exit.
****************************************************************************/
-static bool timeout_processing(int *select_timeout,
+static void timeout_processing(int *select_timeout,
time_t *last_timeout_processing_time)
{
time_t t;
- if (smb_read_error == READ_EOF) {
- DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n"));
- return False;
- }
-
- if (smb_read_error == READ_ERROR) {
- DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n",
- strerror(errno)));
- return False;
- }
-
- if (smb_read_error == READ_BAD_SIG) {
- DEBUG(3,("timeout_processing: receive_smb error bad smb signature. Exiting\n"));
- return False;
- }
-
*last_timeout_processing_time = t = time(NULL);
/* become root again if waiting */
unsigned char trust_passwd_hash[16];
time_t lct;
+ void *lock;
/*
* We're in domain level security, and the code that
* First, open the machine password file with an exclusive lock.
*/
- if (secrets_lock_trust_account_password(lp_workgroup(), True) == False) {
+ lock = secrets_get_trust_account_lock(NULL, lp_workgroup());
+
+ if (lock == NULL) {
DEBUG(0,("process: unable to lock the machine account password for \
machine %s in domain %s.\n", global_myname(), lp_workgroup() ));
- return True;
+ return;
}
if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) {
DEBUG(0,("process: unable to read the machine account password for \
machine %s in domain %s.\n", global_myname(), lp_workgroup()));
- secrets_lock_trust_account_password(lp_workgroup(), False);
- return True;
+ TALLOC_FREE(lock);
+ return;
}
/*
if(t < lct + lp_machine_password_timeout()) {
global_machine_password_needs_changing = False;
- secrets_lock_trust_account_password(lp_workgroup(), False);
- return True;
+ TALLOC_FREE(lock);
+ return;
}
/* always just contact the PDC here */
change_trust_account_password( lp_workgroup(), NULL);
global_machine_password_needs_changing = False;
- secrets_lock_trust_account_password(lp_workgroup(), False);
+ TALLOC_FREE(lock);
}
/* update printer queue caches if necessary */
*select_timeout = setup_select_timeout();
- return True;
+ return;
}
/****************************************************************************
while (True) {
int select_timeout = setup_select_timeout();
int num_echos;
- char *inbuf;
- size_t inbuf_len;
- TALLOC_CTX *frame = talloc_stackframe();
+ char *inbuf = NULL;
+ size_t inbuf_len = 0;
+ bool encrypted = false;
+ TALLOC_CTX *frame = talloc_stackframe_pool(8192);
errno = 0;
/* Did someone ask for immediate checks on things like blocking locks ? */
if (select_timeout == 0) {
- if(!timeout_processing(&select_timeout,
- &last_timeout_processing_time))
- return;
+ timeout_processing(&select_timeout,
+ &last_timeout_processing_time);
num_smbs = 0; /* Reset smb counter. */
}
run_events(smbd_event_context(), 0, NULL, NULL);
- while (!receive_message_or_smb(NULL, &inbuf, &inbuf_len,
- select_timeout, &unread_bytes)) {
- if(!timeout_processing(&select_timeout,
- &last_timeout_processing_time))
- return;
+ while (True) {
+ NTSTATUS status;
+
+ status = receive_message_or_smb(
+ talloc_tos(), &inbuf, &inbuf_len,
+ select_timeout, &unread_bytes, &encrypted);
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ timeout_processing(
+ &select_timeout,
+ &last_timeout_processing_time);
+ continue;
+ }
+
+ DEBUG(3, ("receive_message_or_smb failed: %s, "
+ "exiting\n", nt_errstr(status)));
+ return;
+
num_smbs = 0; /* Reset smb counter. */
}
*/
num_echos = smb_echo_count;
- process_smb(inbuf, inbuf_len, unread_bytes);
+ process_smb(inbuf, inbuf_len, unread_bytes, encrypted);
TALLOC_FREE(inbuf);
if (smb_echo_count != num_echos) {
- if(!timeout_processing( &select_timeout, &last_timeout_processing_time))
- return;
+ timeout_processing(&select_timeout,
+ &last_timeout_processing_time);
num_smbs = 0; /* Reset smb counter. */
}
if ((num_smbs % 200) == 0) {
time_t new_check_time = time(NULL);
if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
- if(!timeout_processing(
- &select_timeout,
- &last_timeout_processing_time))
- return;
+ timeout_processing(
+ &select_timeout,
+ &last_timeout_processing_time);
num_smbs = 0; /* Reset smb counter. */
last_timeout_processing_time = new_check_time; /* Reset time. */
}