/**************************************************************************** raw echo interface (async recv) ****************************************************************************/ NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, struct smb_echo *p) { if (!smbcli_request_receive(req) || smbcli_request_is_error(req)) { goto failed; } SMBCLI_CHECK_WCT(req, 1); p->out.count++; p->out.sequence_number = SVAL(req->in.vwv, VWV(0)); p->out.size = req->in.data_size; talloc_free(p->out.data); p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size); NT_STATUS_HAVE_NO_MEMORY(p->out.data); if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } if (p->out.count == p->in.repeat_count) { return smbcli_request_destroy(req); } return NT_STATUS_OK; failed: return smbcli_request_destroy(req); }
/**************************************************************************** raw write interface (async recv) ****************************************************************************/ NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms) { if (!smbcli_request_receive(req) || !NT_STATUS_IS_OK(req->status)) { goto failed; } switch (parms->generic.level) { case RAW_WRITE_WRITEUNLOCK: SMBCLI_CHECK_WCT(req, 1); parms->writeunlock.out.nwritten = SVAL(req->in.vwv, VWV(0)); break; case RAW_WRITE_WRITE: SMBCLI_CHECK_WCT(req, 1); parms->write.out.nwritten = SVAL(req->in.vwv, VWV(0)); break; case RAW_WRITE_WRITECLOSE: SMBCLI_CHECK_WCT(req, 1); parms->writeclose.out.nwritten = SVAL(req->in.vwv, VWV(0)); break; case RAW_WRITE_WRITEX: SMBCLI_CHECK_WCT(req, 6); parms->writex.out.nwritten = SVAL(req->in.vwv, VWV(2)); parms->writex.out.nwritten += (CVAL(req->in.vwv, VWV(4)) << 16); parms->writex.out.remaining = SVAL(req->in.vwv, VWV(3)); break; case RAW_WRITE_SPLWRITE: break; case RAW_WRITE_SMB2: req->status = NT_STATUS_INTERNAL_ERROR; break; } failed: return smbcli_request_destroy(req); }
/**************************************************************************** Query FS Info - SMBdskattr call (async recv) ****************************************************************************/ static NTSTATUS smb_raw_dskattr_recv(struct smbcli_request *req, union smb_fsinfo *fsinfo) { if (!smbcli_request_receive(req) || smbcli_request_is_error(req)) { goto failed; } SMBCLI_CHECK_WCT(req, 5); fsinfo->dskattr.out.units_total = SVAL(req->in.vwv, VWV(0)); fsinfo->dskattr.out.blocks_per_unit = SVAL(req->in.vwv, VWV(1)); fsinfo->dskattr.out.block_size = SVAL(req->in.vwv, VWV(2)); fsinfo->dskattr.out.units_free = SVAL(req->in.vwv, VWV(3)); failed: return smbcli_request_destroy(req); }
/**************************************************************************** Perform a session setup (async recv) ****************************************************************************/ NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_sesssetup *parms) { uint16_t len; uint8_t *p; if (!smbcli_request_receive(req)) { return smbcli_request_destroy(req); } if (!NT_STATUS_IS_OK(req->status) && !NT_STATUS_EQUAL(req->status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { return smbcli_request_destroy(req); } switch (parms->old.level) { case RAW_SESSSETUP_OLD: SMBCLI_CHECK_WCT(req, 3); ZERO_STRUCT(parms->old.out); parms->old.out.vuid = SVAL(req->in.hdr, HDR_UID); parms->old.out.action = SVAL(req->in.vwv, VWV(2)); p = req->in.data; if (p) { p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE); } break; case RAW_SESSSETUP_NT1: SMBCLI_CHECK_WCT(req, 3); ZERO_STRUCT(parms->nt1.out); parms->nt1.out.vuid = SVAL(req->in.hdr, HDR_UID); parms->nt1.out.action = SVAL(req->in.vwv, VWV(2)); p = req->in.data; if (p) { p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE); if (p < (req->in.data + req->in.data_size)) { p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE); } } break; case RAW_SESSSETUP_SPNEGO: SMBCLI_CHECK_WCT(req, 4); ZERO_STRUCT(parms->spnego.out); parms->spnego.out.vuid = SVAL(req->in.hdr, HDR_UID); parms->spnego.out.action = SVAL(req->in.vwv, VWV(2)); len = SVAL(req->in.vwv, VWV(3)); p = req->in.data; if (!p) { break; } parms->spnego.out.secblob = smbcli_req_pull_blob(&req->in.bufinfo, mem_ctx, p, len); p += parms->spnego.out.secblob.length; p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE); break; case RAW_SESSSETUP_SMB2: req->status = NT_STATUS_INTERNAL_ERROR; break; } failed: return smbcli_request_destroy(req); }
/* Send a negprot command. */ NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req) { struct smbcli_transport *transport = req->transport; int protocol; if (!smbcli_request_receive(req) || smbcli_request_is_error(req)) { return smbcli_request_destroy(req); } SMBCLI_CHECK_MIN_WCT(req, 1); protocol = SVALS(req->in.vwv, VWV(0)); if (protocol >= ARRAY_SIZE(prots) || protocol < 0) { req->status = NT_STATUS_UNSUCCESSFUL; return smbcli_request_destroy(req); } transport->negotiate.protocol = prots[protocol].prot; if (transport->negotiate.protocol >= PROTOCOL_NT1) { NTTIME ntt; /* NT protocol */ SMBCLI_CHECK_WCT(req, 17); transport->negotiate.sec_mode = CVAL(req->in.vwv,VWV(1)); transport->negotiate.max_mux = SVAL(req->in.vwv,VWV(1)+1); transport->negotiate.max_xmit = IVAL(req->in.vwv,VWV(3)+1); transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(7)+1); transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1); /* this time arrives in real GMT */ ntt = smbcli_pull_nttime(req->in.vwv, VWV(11)+1); transport->negotiate.server_time = nt_time_to_unix(ntt); transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60; transport->negotiate.key_len = CVAL(req->in.vwv,VWV(16)+1); if (transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) { if (req->in.data_size < 16) { goto failed; } transport->negotiate.server_guid = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, 16); transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data + 16, req->in.data_size - 16); } else { if (req->in.data_size < (transport->negotiate.key_len)) { goto failed; } transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, transport->negotiate.key_len); smbcli_req_pull_string(&req->in.bufinfo, transport, &transport->negotiate.server_domain, req->in.data+transport->negotiate.key_len, req->in.data_size-transport->negotiate.key_len, STR_UNICODE|STR_NOALIGN); /* here comes the server name */ } if (transport->negotiate.capabilities & CAP_RAW_MODE) { transport->negotiate.readbraw_supported = true; transport->negotiate.writebraw_supported = true; } if (transport->negotiate.capabilities & CAP_LOCK_AND_READ) transport->negotiate.lockread_supported = true; } else if (transport->negotiate.protocol >= PROTOCOL_LANMAN1) { SMBCLI_CHECK_WCT(req, 13); transport->negotiate.sec_mode = SVAL(req->in.vwv,VWV(1)); transport->negotiate.max_xmit = SVAL(req->in.vwv,VWV(2)); transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(6)); transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(10)) * 60; /* this time is converted to GMT by raw_pull_dos_date */ transport->negotiate.server_time = raw_pull_dos_date(transport, req->in.vwv+VWV(8)); if ((SVAL(req->in.vwv,VWV(5)) & 0x1)) { transport->negotiate.readbraw_supported = 1; } if ((SVAL(req->in.vwv,VWV(5)) & 0x2)) { transport->negotiate.writebraw_supported = 1; } transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, req->in.data_size); } else { /* the old core protocol */ transport->negotiate.sec_mode = 0; transport->negotiate.server_time = time(NULL); transport->negotiate.max_xmit = transport->options.max_xmit; transport->negotiate.server_zone = get_time_zone(transport->negotiate.server_time); } /* a way to force ascii SMB */ if (!transport->options.unicode) { transport->negotiate.capabilities &= ~CAP_UNICODE; } if (!transport->options.ntstatus_support) { transport->negotiate.capabilities &= ~CAP_STATUS32; } if (!transport->options.use_level2_oplocks) { transport->negotiate.capabilities &= ~CAP_LEVEL_II_OPLOCKS; } failed: return smbcli_request_destroy(req); }
/**************************************************************************** Open a file - async recv ****************************************************************************/ _PUBLIC_ NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms) { NTSTATUS status; if (!smbcli_request_receive(req) || smbcli_request_is_error(req)) { goto failed; } switch (parms->openold.level) { case RAW_OPEN_T2OPEN: return smb_raw_t2open_recv(req, mem_ctx, parms); case RAW_OPEN_OPEN: SMBCLI_CHECK_WCT(req, 7); parms->openold.out.file.fnum = SVAL(req->in.vwv, VWV(0)); parms->openold.out.attrib = SVAL(req->in.vwv, VWV(1)); parms->openold.out.write_time = raw_pull_dos_date3(req->transport, req->in.vwv + VWV(2)); parms->openold.out.size = IVAL(req->in.vwv, VWV(4)); parms->openold.out.rmode = SVAL(req->in.vwv, VWV(6)); break; case RAW_OPEN_OPENX: SMBCLI_CHECK_MIN_WCT(req, 15); parms->openx.out.file.fnum = SVAL(req->in.vwv, VWV(2)); parms->openx.out.attrib = SVAL(req->in.vwv, VWV(3)); parms->openx.out.write_time = raw_pull_dos_date3(req->transport, req->in.vwv + VWV(4)); parms->openx.out.size = IVAL(req->in.vwv, VWV(6)); parms->openx.out.access = SVAL(req->in.vwv, VWV(8)); parms->openx.out.ftype = SVAL(req->in.vwv, VWV(9)); parms->openx.out.devstate = SVAL(req->in.vwv, VWV(10)); parms->openx.out.action = SVAL(req->in.vwv, VWV(11)); parms->openx.out.unique_fid = IVAL(req->in.vwv, VWV(12)); if (req->in.wct >= 19) { parms->openx.out.access_mask = IVAL(req->in.vwv, VWV(15)); parms->openx.out.unknown = IVAL(req->in.vwv, VWV(17)); } else { parms->openx.out.access_mask = 0; parms->openx.out.unknown = 0; } break; case RAW_OPEN_MKNEW: SMBCLI_CHECK_WCT(req, 1); parms->mknew.out.file.fnum = SVAL(req->in.vwv, VWV(0)); break; case RAW_OPEN_CREATE: SMBCLI_CHECK_WCT(req, 1); parms->create.out.file.fnum = SVAL(req->in.vwv, VWV(0)); break; case RAW_OPEN_CTEMP: SMBCLI_CHECK_WCT(req, 1); parms->ctemp.out.file.fnum = SVAL(req->in.vwv, VWV(0)); smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->ctemp.out.name, req->in.data, -1, STR_TERMINATE | STR_ASCII); break; case RAW_OPEN_SPLOPEN: SMBCLI_CHECK_WCT(req, 1); parms->splopen.out.file.fnum = SVAL(req->in.vwv, VWV(0)); break; case RAW_OPEN_NTCREATEX: SMBCLI_CHECK_MIN_WCT(req, 34); parms->ntcreatex.out.oplock_level = CVAL(req->in.vwv, 4); parms->ntcreatex.out.file.fnum = SVAL(req->in.vwv, 5); parms->ntcreatex.out.create_action = IVAL(req->in.vwv, 7); parms->ntcreatex.out.create_time = smbcli_pull_nttime(req->in.vwv, 11); parms->ntcreatex.out.access_time = smbcli_pull_nttime(req->in.vwv, 19); parms->ntcreatex.out.write_time = smbcli_pull_nttime(req->in.vwv, 27); parms->ntcreatex.out.change_time = smbcli_pull_nttime(req->in.vwv, 35); parms->ntcreatex.out.attrib = IVAL(req->in.vwv, 43); parms->ntcreatex.out.alloc_size = BVAL(req->in.vwv, 47); parms->ntcreatex.out.size = BVAL(req->in.vwv, 55); parms->ntcreatex.out.file_type = SVAL(req->in.vwv, 63); parms->ntcreatex.out.ipc_state = SVAL(req->in.vwv, 65); parms->ntcreatex.out.is_directory = CVAL(req->in.vwv, 67); break; case RAW_OPEN_NTTRANS_CREATE: return smb_raw_nttrans_create_recv(req, mem_ctx, parms); case RAW_OPEN_OPENX_READX: SMBCLI_CHECK_MIN_WCT(req, 15); parms->openxreadx.out.file.fnum = SVAL(req->in.vwv, VWV(2)); parms->openxreadx.out.attrib = SVAL(req->in.vwv, VWV(3)); parms->openxreadx.out.write_time = raw_pull_dos_date3(req->transport, req->in.vwv + VWV(4)); parms->openxreadx.out.size = IVAL(req->in.vwv, VWV(6)); parms->openxreadx.out.access = SVAL(req->in.vwv, VWV(8)); parms->openxreadx.out.ftype = SVAL(req->in.vwv, VWV(9)); parms->openxreadx.out.devstate = SVAL(req->in.vwv, VWV(10)); parms->openxreadx.out.action = SVAL(req->in.vwv, VWV(11)); parms->openxreadx.out.unique_fid = IVAL(req->in.vwv, VWV(12)); if (req->in.wct >= 19) { parms->openxreadx.out.access_mask = IVAL(req->in.vwv, VWV(15)); parms->openxreadx.out.unknown = IVAL(req->in.vwv, VWV(17)); } else { parms->openxreadx.out.access_mask = 0; parms->openxreadx.out.unknown = 0; } status = smbcli_chained_advance(req); if (!NT_STATUS_IS_OK(status)) { return status; } SMBCLI_CHECK_WCT(req, 12); parms->openxreadx.out.remaining = SVAL(req->in.vwv, VWV(2)); parms->openxreadx.out.compaction_mode = SVAL(req->in.vwv, VWV(3)); parms->openxreadx.out.nread = SVAL(req->in.vwv, VWV(5)); if (parms->openxreadx.out.nread > MAX(parms->openxreadx.in.mincnt, parms->openxreadx.in.maxcnt) || !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), parms->openxreadx.out.nread, parms->openxreadx.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } break; case RAW_OPEN_NTCREATEX_READX: SMBCLI_CHECK_MIN_WCT(req, 34); parms->ntcreatexreadx.out.oplock_level = CVAL(req->in.vwv, 4); parms->ntcreatexreadx.out.file.fnum = SVAL(req->in.vwv, 5); parms->ntcreatexreadx.out.create_action = IVAL(req->in.vwv, 7); parms->ntcreatexreadx.out.create_time = smbcli_pull_nttime(req->in.vwv, 11); parms->ntcreatexreadx.out.access_time = smbcli_pull_nttime(req->in.vwv, 19); parms->ntcreatexreadx.out.write_time = smbcli_pull_nttime(req->in.vwv, 27); parms->ntcreatexreadx.out.change_time = smbcli_pull_nttime(req->in.vwv, 35); parms->ntcreatexreadx.out.attrib = IVAL(req->in.vwv, 43); parms->ntcreatexreadx.out.alloc_size = BVAL(req->in.vwv, 47); parms->ntcreatexreadx.out.size = BVAL(req->in.vwv, 55); parms->ntcreatexreadx.out.file_type = SVAL(req->in.vwv, 63); parms->ntcreatexreadx.out.ipc_state = SVAL(req->in.vwv, 65); parms->ntcreatexreadx.out.is_directory = CVAL(req->in.vwv, 67); status = smbcli_chained_advance(req); if (!NT_STATUS_IS_OK(status)) { return status; } SMBCLI_CHECK_WCT(req, 12); parms->ntcreatexreadx.out.remaining = SVAL(req->in.vwv, VWV(2)); parms->ntcreatexreadx.out.compaction_mode = SVAL(req->in.vwv, VWV(3)); parms->ntcreatexreadx.out.nread = SVAL(req->in.vwv, VWV(5)); if (parms->ntcreatexreadx.out.nread > MAX(parms->ntcreatexreadx.in.mincnt, parms->ntcreatexreadx.in.maxcnt) || !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), parms->ntcreatexreadx.out.nread, parms->ntcreatexreadx.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } break; case RAW_OPEN_SMB2: req->status = NT_STATUS_INTERNAL_ERROR; break; } failed: return smbcli_request_destroy(req); }
/**************************************************************************** low level read operation (async recv) ****************************************************************************/ _PUBLIC_ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms) { if (!smbcli_request_receive(req) || smbcli_request_is_error(req)) { goto failed; } switch (parms->generic.level) { case RAW_READ_READBRAW: parms->readbraw.out.nread = req->in.size - NBT_HDR_SIZE; if (parms->readbraw.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; goto failed; } memcpy(parms->readbraw.out.data, req->in.buffer + NBT_HDR_SIZE, parms->readbraw.out.nread); break; case RAW_READ_LOCKREAD: SMBCLI_CHECK_WCT(req, 5); parms->lockread.out.nread = SVAL(req->in.vwv, VWV(0)); if (parms->lockread.out.nread > parms->lockread.in.count || !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3, parms->lockread.out.nread, parms->lockread.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } break; case RAW_READ_READ: /* there are 4 reserved words in the reply */ SMBCLI_CHECK_WCT(req, 5); parms->read.out.nread = SVAL(req->in.vwv, VWV(0)); if (parms->read.out.nread > parms->read.in.count || !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3, parms->read.out.nread, parms->read.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } break; case RAW_READ_READX: /* there are 5 reserved words in the reply */ SMBCLI_CHECK_WCT(req, 12); parms->readx.out.remaining = SVAL(req->in.vwv, VWV(2)); parms->readx.out.compaction_mode = SVAL(req->in.vwv, VWV(3)); parms->readx.out.nread = SVAL(req->in.vwv, VWV(5)); /* handle oversize replies for non-chained readx replies with CAP_LARGE_READX. The snia spec has must to answer for. */ if ((req->tree->session->transport->negotiate.capabilities & CAP_LARGE_READX) && CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE && req->in.size >= 0x10000) { parms->readx.out.nread += (SVAL(req->in.vwv, VWV(7)) << 16); if (req->in.hdr + SVAL(req->in.vwv, VWV(6)) + parms->readx.out.nread <= req->in.buffer + req->in.size) { req->in.data_size += (SVAL(req->in.vwv, VWV(7)) << 16); /* update the bufinfo with the new size */ smb_setup_bufinfo(req); } } if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) || !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), parms->readx.out.nread, parms->readx.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } break; case RAW_READ_SMB2: req->status = NT_STATUS_INTERNAL_ERROR; break; } failed: return smbcli_request_destroy(req); }