#include "includes.h"
-extern struct auth_context *negprot_global_auth_context;
extern int smb_echo_count;
-const int total_buffer_size = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
-static enum smb_read_errors smb_read_error = SMB_READ_OK;
-
/*
* Size of data we can send to client. Set
* by the client for all protocols above CORE.
/* Accessor function for smb_read_error for smbd functions. */
-enum smb_read_errors *get_srv_read_error(void)
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
+
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
{
- return &smb_read_error;
+ 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)
}
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);
}
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)) {
-
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
-
- cond_set_smb_read_error(get_srv_read_error(),
- SMB_READ_ERROR);
- return false;
- }
+ return false;
}
return true;
}
-static ssize_t read_packet_remainder(int fd,
- char *buffer,
- unsigned int timeout,
- ssize_t len)
+static NTSTATUS read_packet_remainder(int fd, char *buffer,
+ unsigned int timeout, ssize_t len)
{
- ssize_t ret;
-
- if(len <= 0) {
- return len;
- }
-
- if (timeout > 0) {
- ret = read_socket_with_timeout(fd,
- buffer,
- len,
- len,
- timeout,
- get_srv_read_error());
- } else {
- ret = read_data(fd, buffer, len, get_srv_read_error());
+ if (len <= 0) {
+ return NT_STATUS_OK;
}
- if (ret != len) {
- cond_set_smb_read_error(get_srv_read_error(),
- SMB_READ_ERROR);
- return -1;
- }
-
- 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,
- get_srv_read_error());
- } else {
- ret = read_data(fd,
- writeX_header+4,
- STANDARD_WRITE_AND_X_HEADER_SIZE,
- get_srv_read_error());
- }
+ 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) {
- cond_set_smb_read_error(get_srv_read_error(),
- SMB_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.
if (*buffer == NULL) {
DEBUG(0, ("Could not allocate inbuf of length %d\n",
(int)sizeof(writeX_header)));
- cond_set_smb_read_error(get_srv_read_error(),
- SMB_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));
- cond_set_smb_read_error(get_srv_read_error(),
- SMB_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;
- set_smb_read_error(get_srv_read_error(),SMB_READ_OK);
*p_unread = 0;
- len = read_smb_length_return_keepalive(fd, lenbuf,
- timeout, get_srv_read_error());
- 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.
- */
-
- cond_set_smb_read_error(get_srv_read_error(),SMB_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 &&
- smb_len_large(lenbuf) > min_recv_size && /* Could be a UNIX large writeX. */
+ 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));
- cond_set_smb_read_error(get_srv_read_error(),SMB_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;
- len = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout, p_unread);
+ *p_encrypted = false;
- if (len < 0) {
- return -1;
+ status = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout,
+ p_unread, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- if (srv_encryption_on()) {
- NTSTATUS status = srv_decrypt_buffer(*buffer);
+ 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) ));
- cond_set_smb_read_error(get_srv_read_error(),
- SMB_READ_BAD_DECRYPT);
- return -1;
+ 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"));
- cond_set_smb_read_error(get_srv_read_error(),SMB_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;
- set_smb_read_error(get_srv_read_error(),SMB_READ_OK);
again:
msg->buf.length);
if (*buffer == NULL) {
DEBUG(0, ("talloc failed\n"));
- set_smb_read_error(get_srv_read_error(),SMB_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? */
- set_smb_read_error(get_srv_read_error(),SMB_READ_ERROR);
- return False;
- }
-
+ return map_nt_error_from_unix(errno);
+ }
+
/* Did we timeout ? */
if (selrtn == 0) {
- set_smb_read_error(get_srv_read_error(),SMB_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);
- 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
if (len < 4) len = smb_len(data)+4;
for (i=1;i<100;i++) {
- asprintf(&fname, "/tmp/%s.%d.%s", name, i,
- type ? "req" : "resp");
- if (!fname) {
+ if (asprintf(&fname, "/tmp/%s.%d.%s", name, i,
+ type ? "req" : "resp") == -1) {
return;
}
fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
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;
/* 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)));
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;
- }
-
- 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++;
}
!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);
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");
}
}
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)
{
- 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);
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 (*get_srv_read_error() == SMB_READ_EOF) {
- DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n"));
- return false;
- }
-
- if (*get_srv_read_error() == SMB_READ_ERROR) {
- DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n",
- strerror(errno)));
- return false;
- }
-
- if (*get_srv_read_error() == SMB_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. */
}