void smb_signing_sign_pdu(struct smb_signing_state *si, uint8_t *outbuf, uint32_t seqnum) { uint8_t calc_md5_mac[16]; uint8_t com; uint8_t flags; if (si->mac_key.length == 0) { if (!si->negotiated) { return; } } /* JRA Paranioa test - we should be able to get rid of this... */ if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) { DEBUG(1,("smb_signing_sign_pdu: Logic error. " "Can't check signature on short packet! smb_len = %u\n", smb_len(outbuf))); abort(); } com = SVAL(outbuf,smb_com); flags = SVAL(outbuf,smb_flg); if (!(flags & FLAG_REPLY)) { uint16_t flags2 = SVAL(outbuf,smb_flg2); /* * If this is a request, specify what is * supported or required by the client */ if (si->negotiated && si->desired) { flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; } if (si->negotiated && si->mandatory) { flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED; } SSVAL(outbuf, smb_flg2, flags2); } if (si->mac_key.length == 0) { /* I wonder what BSRSPYL stands for - but this is what MS actually sends! */ if (com == SMBsesssetupX) { memcpy(calc_md5_mac, "BSRSPYL ", 8); } else { memset(calc_md5_mac, 0, 8); } } else { smb_signing_md5(&si->mac_key, outbuf, seqnum, calc_md5_mac); } DEBUG(10, ("smb_signing_sign_pdu: sent SMB signature of\n")); dump_data(10, calc_md5_mac, 8); memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8); /* outbuf[smb_ss_field+2]=0; Uncomment this to test if the remote server actually verifies signatures...*/ }
bool smb_signing_check_pdu(struct smb_signing_state *si, const uint8_t *inbuf, uint32_t seqnum) { bool good; uint8_t calc_md5_mac[16]; const uint8_t *reply_sent_mac; if (si->mac_key.length == 0) { return true; } if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) { DEBUG(1,("smb_signing_check_pdu: Can't check signature " "on short packet! smb_len = %u\n", smb_len(inbuf))); return False; } smb_signing_md5(&si->mac_key, inbuf, seqnum, calc_md5_mac); reply_sent_mac = &inbuf[smb_ss_field]; good = (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0); if (!good) { int i; const int sign_range = 5; DEBUG(5, ("smb_signing_check_pdu: BAD SIG: wanted SMB signature of\n")); dump_data(5, calc_md5_mac, 8); DEBUG(5, ("smb_signing_check_pdu: BAD SIG: got SMB signature of\n")); dump_data(5, reply_sent_mac, 8); for (i = -sign_range; i < sign_range; i++) { smb_signing_md5(&si->mac_key, inbuf, seqnum+i, calc_md5_mac); if (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0) { DEBUG(0,("smb_signing_check_pdu: " "out of seq. seq num %u matches. " "We were expecting seq %u\n", (unsigned int)seqnum+i, (unsigned int)seqnum)); break; } } } else { DEBUG(10, ("smb_signing_check_pdu: seq %u: " "got good SMB signature of\n", (unsigned int)seqnum)); dump_data(10, reply_sent_mac, 8); } return smb_signing_good(si, good, seqnum); }
BOOL cli_send_smb(struct cli_state *cli) { size_t len; size_t nwritten=0; ssize_t ret; /* fd == -1 causes segfaults -- Tom ([email protected]) */ if (cli->fd == -1) return False; len = smb_len(cli->outbuf) + 4; while (nwritten < len) { ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten); if (ret <= 0) { close(cli->fd); cli->fd = -1; cli->smb_rw_error = WRITE_ERROR; DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", (int)len,(int)ret, strerror(errno) )); return False; } nwritten += ret; } return True; }
ssize_t message_push_string(uint8 **outbuf, const char *str, int flags) { size_t buf_size = smb_len(*outbuf) + 4; size_t grow_size; size_t result = 0; uint8 *tmp; NTSTATUS status; /* * We need to over-allocate, now knowing what srvstr_push will * actually use. This is very generous by incorporating potential * padding, the terminating 0 and at most 4 chars per UTF-16 code * point. */ grow_size = (strlen(str) + 2) * 4; if (!(tmp = talloc_realloc(NULL, *outbuf, uint8, buf_size + grow_size))) { DEBUG(0, ("talloc failed\n")); return -1; } status = srvstr_push((char *)tmp, SVAL(tmp, smb_flg2), tmp + buf_size, str, grow_size, flags, &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("srvstr_push failed\n")); return -1; } set_message_bcc((char *)tmp, smb_buflen(tmp) + result); *outbuf = tmp; return result; }
static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout) { ssize_t len=0; int msg_type; BOOL ok = False; while (!ok) { if (timeout > 0) ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4); else ok = (read_socket_data(fd,inbuf,4) == 4); if (!ok) return(-1); len = smb_len(inbuf); msg_type = CVAL(inbuf,0); if (msg_type == 0x85) DEBUG(5,("Got keepalive packet\n")); } DEBUG(10,("got smb length of %d\n",len)); return(len); }
BOOL push_deferred_smb_message(uint16 mid, struct timeval request_time, struct timeval timeout, char *private_data, size_t priv_len) { struct timeval end_time; end_time = timeval_sum(&request_time, &timeout); DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u " "timeout time [%u.%06u]\n", (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid, (unsigned int)end_time.tv_sec, (unsigned int)end_time.tv_usec)); return push_queued_message(current_inbuf, smb_len(current_inbuf)+4, request_time, end_time, private_data, priv_len); }
bool cli_send_smb(struct cli_state *cli) { size_t len; size_t nwritten=0; ssize_t ret; char *buf_out = cli->outbuf; bool enc_on = cli_encryption_on(cli); /* fd == -1 causes segfaults -- Tom ([email protected]) */ if (cli->fd == -1) return false; cli_calculate_sign_mac(cli, cli->outbuf); if (enc_on) { NTSTATUS status = cli_encrypt_message(cli, cli->outbuf, &buf_out); if (!NT_STATUS_IS_OK(status)) { close(cli->fd); cli->fd = -1; cli->smb_rw_error = SMB_WRITE_ERROR; DEBUG(0,("Error in encrypting client message. Error %s\n", nt_errstr(status) )); return false; } } len = smb_len(buf_out) + 4; while (nwritten < len) { ret = write_socket(cli->fd,buf_out+nwritten,len - nwritten); if (ret <= 0) { if (enc_on) { cli_free_enc_buffer(cli, buf_out); } close(cli->fd); cli->fd = -1; cli->smb_rw_error = SMB_WRITE_ERROR; DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", (int)len,(int)ret, strerror(errno) )); return false; } nwritten += ret; } if (enc_on) { cli_free_enc_buffer(cli, buf_out); } /* Increment the mid so we can tell between responses. */ cli->mid++; if (!cli->mid) cli->mid++; return true; }
void smb_signing_sign_pdu(struct smb_signing_state *si, uint8_t *outbuf, uint32_t seqnum) { uint8_t calc_md5_mac[16]; uint16_t flags2; if (si->mac_key.length == 0) { if (!si->bsrspyl) { return; } } /* JRA Paranioa test - we should be able to get rid of this... */ if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) { DEBUG(1,("smb_signing_sign_pdu: Logic error. " "Can't check signature on short packet! smb_len = %u\n", smb_len(outbuf))); abort(); } /* mark the packet as signed - BEFORE we sign it...*/ flags2 = SVAL(outbuf,smb_flg2); flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; SSVAL(outbuf, smb_flg2, flags2); if (si->bsrspyl) { /* I wonder what BSRSPYL stands for - but this is what MS actually sends! */ memcpy(calc_md5_mac, "BSRSPYL ", 8); } else { smb_signing_md5(&si->mac_key, outbuf, seqnum, calc_md5_mac); } DEBUG(10, ("smb_signing_sign_pdu: sent SMB signature of\n")); dump_data(10, calc_md5_mac, 8); memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8); /* outbuf[smb_ss_field+2]=0; Uncomment this to test if the remote server actually verifies signatures...*/ }
/**************************************************************************** process an smb from the client - split out from the process() code so it can be used by the oplock break code. ****************************************************************************/ void process_smb(char *inbuf, char *outbuf, int ProcSockID, int threadid) { // extern int Client; #ifdef WITH_SSL #endif /* WITH_SSL */ int msg_type = CVAL(inbuf,0); int32 len = smb_len(inbuf); int nread = len + 4; #ifdef WITH_PROFILE profile_p->smb_count++; #endif #ifdef WITH_VTP if(trans_num == 1 && VT_Check(inbuf)) { VT_Process(); return; } #endif if(msg_type == 0x85) return; /* Keepalive packet. */ nread = construct_reply(inbuf,outbuf,nread,max_send[threadid], ProcSockID ,threadid ); if(nread > 0) { if (nread != smb_len(outbuf) + 4) { } else send_smb(ProcSockID,outbuf); } }
void srv_calculate_sign_mac(struct smbd_server_connection *conn, char *outbuf, uint32_t seqnum) { uint8_t *outhdr; size_t len; /* Check if it's a non-session message. */ if(CVAL(outbuf,0)) { return; } len = smb_len(outbuf); outhdr = (uint8_t *)outbuf + NBT_HDR_SIZE; smb_signing_sign_pdu(conn->smb1.signing_state, outhdr, len, seqnum); }
/* setup to receive the data part of the SMB */ static int smb_setup_bcc(struct smb_request *req) { int result = 0; req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd; if (req->rq_rlen > req->rq_bufsize) { PARANOIA("Packet too large %d > %d\n", req->rq_rlen, req->rq_bufsize); return -ENOBUFS; } req->rq_iov[0].iov_base = req->rq_buffer; req->rq_iov[0].iov_len = req->rq_rlen; req->rq_iovlen = 1; return result; }
static int smb_get_length(struct socket *socket, unsigned char *header) { int result; unsigned char peek_buf[4]; mm_segment_t fs; re_recv: fs = get_fs(); set_fs(get_ds()); result = smb_receive_raw(socket, peek_buf, 4); set_fs(fs); if (result < 0) { #ifdef SMBFS_PARANOIA printk("smb_get_length: recv error = %d\n", -result); #endif return result; } switch (peek_buf[0]) { case 0x00: case 0x82: break; case 0x85: pr_debug("smb_get_length: Got SESSION KEEP ALIVE\n"); goto re_recv; default: #ifdef SMBFS_PARANOIA printk("smb_get_length: Invalid NBT packet, code=%x\n", peek_buf[0]); #endif return -EIO; } if (header != NULL) { memcpy(header, peek_buf, 4); } /* The length in the RFC NB header is the raw data length */ return smb_len(peek_buf); }
/* * Prepare a "normal" request structure. */ static int smb_setup_request(struct smb_request *req) { int len = smb_len(req->rq_header) + 4; req->rq_slen = len; /* if we expect a data part in the reply we set the iov's to read it */ if (req->rq_resp_bcc) req->rq_setup_read = smb_setup_bcc; /* This tries to support re-using the same request */ req->rq_bytes_sent = 0; req->rq_rcls = 0; req->rq_err = 0; req->rq_errno = 0; req->rq_fragment = 0; kfree(req->rq_trans2buffer); return 0; }
static void smb_signing_md5(const DATA_BLOB *mac_key, const uint8_t *buf, uint32_t seq_number, uint8_t calc_md5_mac[16]) { const size_t offset_end_of_sig = (smb_ss_field + 8); uint8_t sequence_buf[8]; struct MD5Context md5_ctx; /* * Firstly put the sequence number into the first 4 bytes. * and zero out the next 4 bytes. * * We do this here, to avoid modifying the packet. */ DEBUG(10,("smb_signing_md5: sequence number %u\n", seq_number )); SIVAL(sequence_buf, 0, seq_number); SIVAL(sequence_buf, 4, 0); /* Calculate the 16 byte MAC - but don't alter the data in the incoming packet. This makes for a bit of fussing about, but it's not too bad. */ MD5Init(&md5_ctx); /* intialise with the key */ MD5Update(&md5_ctx, mac_key->data, mac_key->length); /* copy in the first bit of the SMB header */ MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4); /* copy in the sequence number, instead of the signature */ MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf)); /* copy in the rest of the packet in, skipping the signature */ MD5Update(&md5_ctx, buf + offset_end_of_sig, smb_len(buf) - (offset_end_of_sig - 4)); /* calculate the MD5 sig */ MD5Final(calc_md5_mac, &md5_ctx); }
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; }
bool srv_check_sign_mac(struct smbd_server_connection *conn, const char *inbuf, uint32_t *seqnum, bool trusted_channel) { const uint8_t *inhdr; size_t len; /* Check if it's a non-session message. */ if(CVAL(inbuf,0)) { return true; } len = smb_len(inbuf); inhdr = (const uint8_t *)inbuf + NBT_HDR_SIZE; if (trusted_channel) { NTSTATUS status; if (len < (HDR_SS_FIELD + 8)) { DEBUG(1,("smb_signing_check_pdu: Can't check signature " "on short packet! smb_len = %u\n", (unsigned)len)); return false; } status = NT_STATUS(IVAL(inhdr, HDR_SS_FIELD + 4)); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("smb_signing_check_pdu: trusted channel passed %s\n", nt_errstr(status))); return false; } *seqnum = IVAL(inhdr, HDR_SS_FIELD); return true; } *seqnum = smb_signing_next_seqnum(conn->smb1.signing_state, false); return smb_signing_check_pdu(conn->smb1.signing_state, inhdr, len, *seqnum); }
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_socket(fd,buffer+nwritten,len - nwritten); if (ret <= 0) { DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",(int)len,(int)ret)); close_sockets(); exit(1); } nwritten += ret; } return True; }
BOOL send_smb(int fd,char *buffer) { size_t len; size_t nwritten=0; ssize_t ret; /* Sign the outgoing packet if required. */ srv_calculate_sign_mac(buffer); len = smb_len(buffer) + 4; while (nwritten < len) { ret = write_socket(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 int reply_lanman1(char *inbuf, char *outbuf) { int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); int secword=0; time_t t = time(NULL); global_encrypted_passwords_negotiated = lp_encrypted_passwords(); if (lp_security()>=SEC_USER) secword |= NEGOTIATE_SECURITY_USER_LEVEL; if (global_encrypted_passwords_negotiated) secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); SSVAL(outbuf,smb_vwv1,secword); /* Create a token value and add it to the outgoing packet. */ if (global_encrypted_passwords_negotiated) { get_challenge(smb_buf(outbuf)); SSVAL(outbuf,smb_vwv11, 8); } Protocol = PROTOCOL_LANMAN1; /* Reply, SMBlockread, SMBwritelock supported. */ SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); SSVAL(outbuf,smb_vwv2,max_recv); SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */ SSVAL(outbuf,smb_vwv4,1); SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support readbraw writebraw (possibly) */ SIVAL(outbuf,smb_vwv6,sys_getpid()); SSVAL(outbuf,smb_vwv10, set_server_zone_offset(t)/60); srv_put_dos_date(outbuf,smb_vwv8,t); return (smb_len(outbuf)+4); }
NTSTATUS read_smb_length_return_keepalive(int fd, char *inbuf, unsigned int timeout, size_t *len) { int msg_type; NTSTATUS status; status = read_fd_with_timeout(fd, inbuf, 4, 4, timeout, NULL); if (!NT_STATUS_IS_OK(status)) { return status; } *len = smb_len(inbuf); msg_type = CVAL(inbuf,0); if (msg_type == NBSSkeepalive) { DEBUG(5,("Got keepalive packet\n")); } DEBUG(10,("got smb length of %lu\n",(unsigned long)(*len))); return NT_STATUS_OK; }
static int reply_nt1(char *inbuf, char *outbuf) { /* dual names + lock_and_read + nt SMBs + remote API calls */ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ| CAP_LEVEL_II_OPLOCKS; int secword=0; char *p, *q; BOOL negotiate_spnego = False; time_t t = time(NULL); global_encrypted_passwords_negotiated = lp_encrypted_passwords(); /* Check the flags field to see if this is Vista. WinXP sets it and Vista does not. But we have to distinguish from NT which doesn't set it either. */ if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) && ((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) ) { /* Don't override the SAMBA or CIFSFS arch */ if ((get_remote_arch() != RA_SAMBA) && (get_remote_arch() != RA_CIFSFS)) { set_remote_arch( RA_VISTA ); } } /* do spnego in user level security if the client supports it and we can do encrypted passwords */ if (global_encrypted_passwords_negotiated && (lp_security() != SEC_SHARE) && lp_use_spnego() && (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { negotiate_spnego = True; capabilities |= CAP_EXTENDED_SECURITY; add_to_common_flags2(FLAGS2_EXTENDED_SECURITY); /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already partially constructed. */ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_EXTENDED_SECURITY); } capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE; if (lp_unix_extensions()) { capabilities |= CAP_UNIX; } if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS; if (SMB_OFF_T_BITS == 64) capabilities |= CAP_LARGE_FILES; if (lp_readraw() && lp_writeraw()) capabilities |= CAP_RAW_MODE; if (lp_nt_status_support()) capabilities |= CAP_STATUS32; if (lp_host_msdfs()) capabilities |= CAP_DFS; if (lp_security() >= SEC_USER) secword |= NEGOTIATE_SECURITY_USER_LEVEL; if (global_encrypted_passwords_negotiated) secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; if (lp_server_signing()) { if (lp_security() >= SEC_USER) { secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED; /* No raw mode with smb signing. */ capabilities &= ~CAP_RAW_MODE; if (lp_server_signing() == Required) secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; srv_set_signing_negotiated(); } else { DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n")); if (lp_server_signing() == Required) { exit_server_cleanly("reply_nt1: smb signing required and share level security selected."); } } } set_message(outbuf,17,0,True); SCVAL(outbuf,smb_vwv1,secword); Protocol = PROTOCOL_NT1; SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */ SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */ SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */ SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */ SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */ put_long_date(outbuf+smb_vwv11+1,t); SSVALS(outbuf,smb_vwv15+1,set_server_zone_offset(t)/60); p = q = smb_buf(outbuf); if (!negotiate_spnego) { /* Create a token value and add it to the outgoing packet. */ if (global_encrypted_passwords_negotiated) { /* note that we do not send a challenge at all if we are using plaintext */ get_challenge(p); SCVAL(outbuf,smb_vwv16+1,8); p += 8; } p += srvstr_push(outbuf, p, lp_workgroup(), BUFFER_SIZE - (p-outbuf), STR_UNICODE|STR_TERMINATE|STR_NOALIGN); DEBUG(3,("not using SPNEGO\n")); } else { DATA_BLOB spnego_blob = negprot_spnego(); if (spnego_blob.data == NULL) { return ERROR_NT(NT_STATUS_NO_MEMORY); } memcpy(p, spnego_blob.data, spnego_blob.length); p += spnego_blob.length; data_blob_free(&spnego_blob); SCVAL(outbuf,smb_vwv16+1, 0); DEBUG(3,("using SPNEGO\n")); } SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */ set_message_end(outbuf, p); return (smb_len(outbuf)+4); }
static NTSTATUS cli_pull_trans(uint8_t *inbuf, uint8_t wct, uint16_t *vwv, uint16_t num_bytes, uint8_t *bytes, uint8_t smb_cmd, bool expect_first_reply, uint8_t *pnum_setup, uint16_t **psetup, uint32_t *ptotal_param, uint32_t *pnum_param, uint32_t *pparam_disp, uint8_t **pparam, uint32_t *ptotal_data, uint32_t *pnum_data, uint32_t *pdata_disp, uint8_t **pdata) { uint32_t param_ofs, data_ofs; if (expect_first_reply) { if ((wct != 0) || (num_bytes != 0)) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } return NT_STATUS_OK; } switch (smb_cmd) { case SMBtrans: case SMBtrans2: if (wct < 10) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } *ptotal_param = SVAL(vwv + 0, 0); *ptotal_data = SVAL(vwv + 1, 0); *pnum_param = SVAL(vwv + 3, 0); param_ofs = SVAL(vwv + 4, 0); *pparam_disp = SVAL(vwv + 5, 0); *pnum_data = SVAL(vwv + 6, 0); data_ofs = SVAL(vwv + 7, 0); *pdata_disp = SVAL(vwv + 8, 0); *pnum_setup = CVAL(vwv + 9, 0); if (wct < 10 + (*pnum_setup)) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } *psetup = vwv + 10; break; case SMBnttrans: if (wct < 18) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } *ptotal_param = IVAL(vwv, 3); *ptotal_data = IVAL(vwv, 7); *pnum_param = IVAL(vwv, 11); param_ofs = IVAL(vwv, 15); *pparam_disp = IVAL(vwv, 19); *pnum_data = IVAL(vwv, 23); data_ofs = IVAL(vwv, 27); *pdata_disp = IVAL(vwv, 31); *pnum_setup = CVAL(vwv, 35); *psetup = vwv + 18; break; default: return NT_STATUS_INTERNAL_ERROR; } /* * Check for buffer overflows. data_ofs needs to be checked against * the incoming buffer length, data_disp against the total * length. Likewise for param_ofs/param_disp. */ if (trans_oob(smb_len(inbuf), param_ofs, *pnum_param) || trans_oob(*ptotal_param, *pparam_disp, *pnum_param) || trans_oob(smb_len(inbuf), data_ofs, *pnum_data) || trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } *pparam = (uint8_t *)inbuf + 4 + param_ofs; *pdata = (uint8_t *)inbuf + 4 + data_ofs; return NT_STATUS_OK; }
/* * Called with the server locked */ int smb_request(struct smb_sb_info *server) { unsigned long flags, sigpipe; mm_segment_t fs; sigset_t old_set; int len, result; unsigned char *buffer; result = -EBADF; buffer = server->packet; if (!buffer) goto bad_no_packet; result = -EIO; if (server->state != CONN_VALID) goto bad_no_conn; if ((result = smb_dont_catch_keepalive(server)) != 0) goto bad_conn; len = smb_len(buffer) + 4; DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]); spin_lock_irqsave(¤t->sigmask_lock, flags); sigpipe = sigismember(¤t->signal, SIGPIPE); old_set = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); fs = get_fs(); set_fs(get_ds()); result = smb_send_raw(server_sock(server), (void *) buffer, len); if (result > 0) { result = smb_receive(server); } /* read/write errors are handled by errno */ spin_lock_irqsave(¤t->sigmask_lock, flags); if (result == -EPIPE && !sigpipe) sigdelset(¤t->signal, SIGPIPE); current->blocked = old_set; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); set_fs(fs); if (result >= 0) { int result2 = smb_catch_keepalive(server); if (result2 < 0) { printk(KERN_ERR "smb_request: catch keepalive failed\n"); result = result2; } } if (result < 0) goto bad_conn; /* * Check for fatal server errors ... */ if (server->rcls) { int error = smb_errno(server); if (error == EBADSLT) { printk(KERN_ERR "smb_request: tree ID invalid\n"); result = error; goto bad_conn; } } out: DEBUG1("result = %d\n", result); return result; bad_conn: PARANOIA("result %d, setting invalid\n", result); server->state = CONN_INVALID; smb_invalidate_inodes(server); goto out; bad_no_packet: printk(KERN_ERR "smb_request: no packet!\n"); goto out; bad_no_conn: printk(KERN_ERR "smb_request: connection %d not valid!\n", server->state); goto out; }
bool cli_receive_smb(struct cli_state *cli) { ssize_t len; uint16_t mid; uint32_t seqnum; /* fd == -1 causes segfaults -- Tom ([email protected]) */ if (cli->fd == -1) return false; again: len = client_receive_smb(cli, 0); if (len > 0) { /* it might be an oplock break request */ if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) && CVAL(cli->inbuf,smb_com) == SMBlockingX && SVAL(cli->inbuf,smb_vwv6) == 0 && SVAL(cli->inbuf,smb_vwv7) == 0) { if (cli->oplock_handler) { int fnum = SVAL(cli->inbuf,smb_vwv2); unsigned char level = CVAL(cli->inbuf,smb_vwv3+1); if (!NT_STATUS_IS_OK(cli->oplock_handler(cli, fnum, level))) { return false; } } /* try to prevent loops */ SCVAL(cli->inbuf,smb_com,0xFF); goto again; } } /* If the server is not responding, note that now */ if (len < 0) { DEBUG(0, ("Receiving SMB: Server stopped responding\n")); close(cli->fd); cli->fd = -1; return false; } mid = SVAL(cli->inbuf,smb_mid); seqnum = cli_state_get_seqnum(cli, mid); if (!cli_check_sign_mac(cli, cli->inbuf, seqnum+1)) { /* * If we get a signature failure in sessionsetup, then * the server sometimes just reflects the sent signature * back to us. Detect this and allow the upper layer to * retrieve the correct Windows error message. */ if (CVAL(cli->outbuf,smb_com) == SMBsesssetupX && (smb_len(cli->inbuf) > (smb_ss_field + 8 - 4)) && (SVAL(cli->inbuf,smb_flg2) & FLAGS2_SMB_SECURITY_SIGNATURES) && memcmp(&cli->outbuf[smb_ss_field],&cli->inbuf[smb_ss_field],8) == 0 && cli_is_error(cli)) { /* * Reflected signature on login error. * Set bad sig but don't close fd. */ cli->smb_rw_error = SMB_READ_BAD_SIG; return true; } DEBUG(0, ("SMB Signature verification failed on incoming packet!\n")); cli->smb_rw_error = SMB_READ_BAD_SIG; close(cli->fd); cli->fd = -1; return false; }; return true; }