/* Open a file using TRANSACT2_OPEN - async recv */ static NTSTATUS smb_raw_nttrans_create_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms) { NTSTATUS status; struct smb_nttrans nt; uint8_t *params; status = smb_raw_nttrans_recv(req, mem_ctx, &nt); if (!NT_STATUS_IS_OK(status)) return status; if (nt.out.params.length < 69) { return NT_STATUS_INVALID_PARAMETER; } params = nt.out.params.data; parms->ntcreatex.out.oplock_level = CVAL(params, 0); parms->ntcreatex.out.file.fnum = SVAL(params, 2); parms->ntcreatex.out.create_action = IVAL(params, 4); parms->ntcreatex.out.create_time = smbcli_pull_nttime(params, 12); parms->ntcreatex.out.access_time = smbcli_pull_nttime(params, 20); parms->ntcreatex.out.write_time = smbcli_pull_nttime(params, 28); parms->ntcreatex.out.change_time = smbcli_pull_nttime(params, 36); parms->ntcreatex.out.attrib = IVAL(params, 44); parms->ntcreatex.out.alloc_size = BVAL(params, 48); parms->ntcreatex.out.size = BVAL(params, 56); parms->ntcreatex.out.file_type = SVAL(params, 64); parms->ntcreatex.out.ipc_state = SVAL(params, 66); parms->ntcreatex.out.is_directory = CVAL(params, 68); return NT_STATUS_OK; }
/* recv a create reply */ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io) { NTSTATUS status; if (!smb2_request_receive(req) || !smb2_request_is_ok(req)) { return smb2_request_destroy(req); } SMB2_CHECK_PACKET_RECV(req, 0x58, True); io->out.oplock_flags = SVAL(req->in.body, 0x02); io->out.create_action = IVAL(req->in.body, 0x04); io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08); io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10); io->out.write_time = smbcli_pull_nttime(req->in.body, 0x18); io->out.change_time = smbcli_pull_nttime(req->in.body, 0x20); io->out.alloc_size = BVAL(req->in.body, 0x28); io->out.size = BVAL(req->in.body, 0x30); io->out.file_attr = IVAL(req->in.body, 0x38); io->out._pad = IVAL(req->in.body, 0x3C); smb2_pull_handle(req->in.body+0x40, &io->out.file.handle); status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &io->out.blob); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } return smb2_request_destroy(req); }
void smb2srv_negprot_recv(struct smb2srv_request *req) { struct smb2_negprot *io; int i; if (req->in.body_size < 0x26) { smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot"); return; } io = talloc(req, struct smb2_negprot); if (!io) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY)); talloc_free(req); return; } io->in.dialect_count = SVAL(req->in.body, 0x02); io->in.security_mode = SVAL(req->in.body, 0x04); io->in.reserved = SVAL(req->in.body, 0x06); io->in.capabilities = IVAL(req->in.body, 0x08); req->status = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid); if (!NT_STATUS_IS_OK(req->status)) { smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot"); talloc_free(req); return; } io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C); io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count); if (io->in.dialects == NULL) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY)); talloc_free(req); return; } for (i=0;i<io->in.dialect_count;i++) { io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2); } req->status = smb2srv_negprot_backend(req, io); if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) { talloc_free(req); return; } smb2srv_negprot_send(req, io); }
/* 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); }
/* parse a trans2 search response. Return the number of bytes consumed return 0 for success with end of list return -1 for a parse error */ static int parse_trans2_search(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, enum smb_search_data_level level, uint16_t flags, DATA_BLOB *blob, union smb_search_data *data) { unsigned int len, ofs; uint32_t ea_size; DATA_BLOB eablob; NTSTATUS status; switch (level) { case RAW_SEARCH_DATA_GENERIC: case RAW_SEARCH_DATA_SEARCH: /* handled elsewhere */ return -1; case RAW_SEARCH_DATA_STANDARD: if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { if (blob->length < 4) return -1; data->standard.resume_key = IVAL(blob->data, 0); blob->data += 4; blob->length -= 4; } if (blob->length < 24) return -1; data->standard.create_time = raw_pull_dos_date2(tree->session->transport, blob->data + 0); data->standard.access_time = raw_pull_dos_date2(tree->session->transport, blob->data + 4); data->standard.write_time = raw_pull_dos_date2(tree->session->transport, blob->data + 8); data->standard.size = IVAL(blob->data, 12); data->standard.alloc_size = IVAL(blob->data, 16); data->standard.attrib = SVAL(blob->data, 20); len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, &data->standard.name, 22, 23, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM); return len + 23; case RAW_SEARCH_DATA_EA_SIZE: if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { if (blob->length < 4) return -1; data->ea_size.resume_key = IVAL(blob->data, 0); blob->data += 4; blob->length -= 4; } if (blob->length < 28) return -1; data->ea_size.create_time = raw_pull_dos_date2(tree->session->transport, blob->data + 0); data->ea_size.access_time = raw_pull_dos_date2(tree->session->transport, blob->data + 4); data->ea_size.write_time = raw_pull_dos_date2(tree->session->transport, blob->data + 8); data->ea_size.size = IVAL(blob->data, 12); data->ea_size.alloc_size = IVAL(blob->data, 16); data->ea_size.attrib = SVAL(blob->data, 20); data->ea_size.ea_size = IVAL(blob->data, 22); len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, &data->ea_size.name, 26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN); return len + 27 + 1; case RAW_SEARCH_DATA_EA_LIST: if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { if (blob->length < 4) return -1; data->ea_list.resume_key = IVAL(blob->data, 0); blob->data += 4; blob->length -= 4; } if (blob->length < 28) return -1; data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport, blob->data + 0); data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport, blob->data + 4); data->ea_list.write_time = raw_pull_dos_date2(tree->session->transport, blob->data + 8); data->ea_list.size = IVAL(blob->data, 12); data->ea_list.alloc_size = IVAL(blob->data, 16); data->ea_list.attrib = SVAL(blob->data, 20); ea_size = IVAL(blob->data, 22); if (ea_size > 0xFFFF) { return -1; } eablob.data = blob->data + 22; eablob.length = ea_size; if (eablob.length > blob->length - 24) { return -1; } status = ea_pull_list(&eablob, mem_ctx, &data->ea_list.eas.num_eas, &data->ea_list.eas.eas); if (!NT_STATUS_IS_OK(status)) { return -1; } len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, &data->ea_list.name, 22+ea_size, 23+ea_size, STR_LEN8BIT | STR_NOALIGN); return len + ea_size + 23 + 1; case RAW_SEARCH_DATA_UNIX_INFO: if (blob->length < 109) return -1; ofs = IVAL(blob->data, 0); data->unix_info.file_index = IVAL(blob->data, 4); data->unix_info.size = BVAL(blob->data, 8); data->unix_info.alloc_size = BVAL(blob->data, 16); data->unix_info.status_change_time = smbcli_pull_nttime(blob->data, 24); data->unix_info.access_time = smbcli_pull_nttime(blob->data, 32); data->unix_info.change_time = smbcli_pull_nttime(blob->data, 40); data->unix_info.uid = IVAL(blob->data, 48); data->unix_info.gid = IVAL(blob->data, 56); data->unix_info.file_type = IVAL(blob->data, 64); data->unix_info.dev_major = BVAL(blob->data, 68); data->unix_info.dev_minor = BVAL(blob->data, 76); data->unix_info.unique_id = BVAL(blob->data, 84); data->unix_info.permissions = IVAL(blob->data, 92); data->unix_info.nlink = IVAL(blob->data, 100); /* There is no length field for this name but we know it's null terminated. */ len = smbcli_blob_pull_unix_string(tree->session, mem_ctx, blob, &data->unix_info.name, 108, 0); if (ofs != 0 && ofs < 108+len) { return -1; } return ofs; case RAW_SEARCH_DATA_UNIX_INFO2: /* 8 - size of ofs + file_index * 116 - size of unix_info2 * 4 - size of name length * 2 - "." is the shortest name */ if (blob->length < (116 + 8 + 4 + 2)) { return -1; } ofs = IVAL(blob->data, 0); data->unix_info2.file_index = IVAL(blob->data, 4); data->unix_info2.end_of_file = BVAL(blob->data, 8); data->unix_info2.num_bytes = BVAL(blob->data, 16); data->unix_info2.status_change_time = smbcli_pull_nttime(blob->data, 24); data->unix_info2.access_time = smbcli_pull_nttime(blob->data, 32); data->unix_info2.change_time = smbcli_pull_nttime(blob->data, 40); data->unix_info2.uid = IVAL(blob->data, 48); data->unix_info2.gid = IVAL(blob->data, 56); data->unix_info2.file_type = IVAL(blob->data, 64); data->unix_info2.dev_major = BVAL(blob->data, 68); data->unix_info2.dev_minor = BVAL(blob->data, 76); data->unix_info2.unique_id = BVAL(blob->data, 84); data->unix_info2.permissions = IVAL(blob->data, 92); data->unix_info2.nlink = IVAL(blob->data, 100); data->unix_info2.create_time = smbcli_pull_nttime(blob->data, 108); data->unix_info2.file_flags = IVAL(blob->data, 116); data->unix_info2.flags_mask = IVAL(blob->data, 120); /* There is a 4 byte length field for this name. The length * does not include the NULL terminator. */ len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, &data->unix_info2.name, 8 + 116, /* offset to length */ 8 + 116 + 4, /* offset to string */ 0); if (ofs != 0 && ofs < (8 + 116 + 4 + len)) { return -1; } return ofs; case RAW_SEARCH_DATA_DIRECTORY_INFO: case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: case RAW_SEARCH_DATA_NAME_INFO: case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO: case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO: case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: { unsigned int str_flags = STR_UNICODE; if (!(tree->session->transport->negotiate.capabilities & CAP_UNICODE)) { str_flags = STR_ASCII; } status = smb_raw_search_common(mem_ctx, level, blob, data, &ofs, str_flags); if (!NT_STATUS_IS_OK(status)) { return -1; } return ofs; } } /* invalid level */ return -1; }
/* parse the wire search formats that are in common between SMB and SMB2 */ NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx, enum smb_search_data_level level, const DATA_BLOB *blob, union smb_search_data *data, unsigned int *next_ofs, unsigned int str_flags) { unsigned int len, blen; if (blob->length < 4) { return NT_STATUS_INFO_LENGTH_MISMATCH; } *next_ofs = IVAL(blob->data, 0); if (*next_ofs != 0) { blen = *next_ofs; } else { blen = blob->length; } switch (level) { case RAW_SEARCH_DATA_DIRECTORY_INFO: if (blen < 65) return NT_STATUS_INFO_LENGTH_MISMATCH; data->directory_info.file_index = IVAL(blob->data, 4); data->directory_info.create_time = smbcli_pull_nttime(blob->data, 8); data->directory_info.access_time = smbcli_pull_nttime(blob->data, 16); data->directory_info.write_time = smbcli_pull_nttime(blob->data, 24); data->directory_info.change_time = smbcli_pull_nttime(blob->data, 32); data->directory_info.size = BVAL(blob->data, 40); data->directory_info.alloc_size = BVAL(blob->data, 48); data->directory_info.attrib = IVAL(blob->data, 56); len = smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->directory_info.name, 60, 64, str_flags); if (*next_ofs != 0 && *next_ofs < 64+len) { return NT_STATUS_INFO_LENGTH_MISMATCH; } return NT_STATUS_OK; case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: if (blen < 69) return NT_STATUS_INFO_LENGTH_MISMATCH; data->full_directory_info.file_index = IVAL(blob->data, 4); data->full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); data->full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); data->full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); data->full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); data->full_directory_info.size = BVAL(blob->data, 40); data->full_directory_info.alloc_size = BVAL(blob->data, 48); data->full_directory_info.attrib = IVAL(blob->data, 56); data->full_directory_info.ea_size = IVAL(blob->data, 64); len = smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->full_directory_info.name, 60, 68, str_flags); if (*next_ofs != 0 && *next_ofs < 68+len) { return NT_STATUS_INFO_LENGTH_MISMATCH; } return NT_STATUS_OK; case RAW_SEARCH_DATA_NAME_INFO: if (blen < 13) return NT_STATUS_INFO_LENGTH_MISMATCH; data->name_info.file_index = IVAL(blob->data, 4); len = smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->name_info.name, 8, 12, str_flags); if (*next_ofs != 0 && *next_ofs < 12+len) { return NT_STATUS_INFO_LENGTH_MISMATCH; } return NT_STATUS_OK; case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO: if (blen < 95) return NT_STATUS_INFO_LENGTH_MISMATCH; data->both_directory_info.file_index = IVAL(blob->data, 4); data->both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); data->both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); data->both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); data->both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); data->both_directory_info.size = BVAL(blob->data, 40); data->both_directory_info.alloc_size = BVAL(blob->data, 48); data->both_directory_info.attrib = IVAL(blob->data, 56); data->both_directory_info.ea_size = IVAL(blob->data, 64); smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->both_directory_info.short_name, 68, 70, STR_LEN8BIT | STR_UNICODE); len = smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->both_directory_info.name, 60, 94, str_flags); if (*next_ofs != 0 && *next_ofs < 94+len) { return NT_STATUS_INFO_LENGTH_MISMATCH; } return NT_STATUS_OK; case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO: if (blen < 81) return NT_STATUS_INFO_LENGTH_MISMATCH; data->id_full_directory_info.file_index = IVAL(blob->data, 4); data->id_full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); data->id_full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); data->id_full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); data->id_full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); data->id_full_directory_info.size = BVAL(blob->data, 40); data->id_full_directory_info.alloc_size = BVAL(blob->data, 48); data->id_full_directory_info.attrib = IVAL(blob->data, 56); data->id_full_directory_info.ea_size = IVAL(blob->data, 64); data->id_full_directory_info.file_id = BVAL(blob->data, 72); len = smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->id_full_directory_info.name, 60, 80, str_flags); if (*next_ofs != 0 && *next_ofs < 80+len) { return NT_STATUS_INFO_LENGTH_MISMATCH; } return NT_STATUS_OK; case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: if (blen < 105) return NT_STATUS_INFO_LENGTH_MISMATCH; data->id_both_directory_info.file_index = IVAL(blob->data, 4); data->id_both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8); data->id_both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16); data->id_both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24); data->id_both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32); data->id_both_directory_info.size = BVAL(blob->data, 40); data->id_both_directory_info.alloc_size = BVAL(blob->data, 48); data->id_both_directory_info.attrib = SVAL(blob->data, 56); data->id_both_directory_info.ea_size = IVAL(blob->data, 64); smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->id_both_directory_info.short_name, 68, 70, STR_LEN8BIT | STR_UNICODE); memcpy(data->id_both_directory_info.short_name_buf, blob->data + 70, 24); data->id_both_directory_info.file_id = BVAL(blob->data, 96); len = smbcli_blob_pull_string(NULL, mem_ctx, blob, &data->id_both_directory_info.name, 60, 104, str_flags); if (*next_ofs != 0 && *next_ofs < 104+len) { return NT_STATUS_INFO_LENGTH_MISMATCH; } return NT_STATUS_OK; default: break; } /* invalid level */ return NT_STATUS_INVALID_INFO_CLASS; }
/* parse the fsinfo 'passthru' level replies */ NTSTATUS smb_raw_fsinfo_passthru_parse(DATA_BLOB blob, TALLOC_CTX *mem_ctx, enum smb_fsinfo_level level, union smb_fsinfo *fsinfo) { NTSTATUS status = NT_STATUS_OK; int i; /* parse the results */ switch (level) { case RAW_QFS_VOLUME_INFORMATION: QFS_CHECK_MIN_SIZE(18); fsinfo->volume_info.out.create_time = smbcli_pull_nttime(blob.data, 0); fsinfo->volume_info.out.serial_number = IVAL(blob.data, 8); smbcli_blob_pull_string(NULL, mem_ctx, &blob, &fsinfo->volume_info.out.volume_name, 12, 18, STR_UNICODE); break; case RAW_QFS_SIZE_INFORMATION: QFS_CHECK_SIZE(24); fsinfo->size_info.out.total_alloc_units = BVAL(blob.data, 0); fsinfo->size_info.out.avail_alloc_units = BVAL(blob.data, 8); fsinfo->size_info.out.sectors_per_unit = IVAL(blob.data, 16); fsinfo->size_info.out.bytes_per_sector = IVAL(blob.data, 20); break; case RAW_QFS_DEVICE_INFORMATION: QFS_CHECK_SIZE(8); fsinfo->device_info.out.device_type = IVAL(blob.data, 0); fsinfo->device_info.out.characteristics = IVAL(blob.data, 4); break; case RAW_QFS_ATTRIBUTE_INFORMATION: QFS_CHECK_MIN_SIZE(12); fsinfo->attribute_info.out.fs_attr = IVAL(blob.data, 0); fsinfo->attribute_info.out.max_file_component_length = IVAL(blob.data, 4); smbcli_blob_pull_string(NULL, mem_ctx, &blob, &fsinfo->attribute_info.out.fs_type, 8, 12, STR_UNICODE); break; case RAW_QFS_QUOTA_INFORMATION: QFS_CHECK_SIZE(48); fsinfo->quota_information.out.unknown[0] = BVAL(blob.data, 0); fsinfo->quota_information.out.unknown[1] = BVAL(blob.data, 8); fsinfo->quota_information.out.unknown[2] = BVAL(blob.data, 16); fsinfo->quota_information.out.quota_soft = BVAL(blob.data, 24); fsinfo->quota_information.out.quota_hard = BVAL(blob.data, 32); fsinfo->quota_information.out.quota_flags = BVAL(blob.data, 40); break; case RAW_QFS_FULL_SIZE_INFORMATION: QFS_CHECK_SIZE(32); fsinfo->full_size_information.out.total_alloc_units = BVAL(blob.data, 0); fsinfo->full_size_information.out.call_avail_alloc_units = BVAL(blob.data, 8); fsinfo->full_size_information.out.actual_avail_alloc_units = BVAL(blob.data, 16); fsinfo->full_size_information.out.sectors_per_unit = IVAL(blob.data, 24); fsinfo->full_size_information.out.bytes_per_sector = IVAL(blob.data, 28); break; case RAW_QFS_OBJECTID_INFORMATION: QFS_CHECK_SIZE(64); status = ndr_pull_struct_blob(&blob, mem_ctx, &fsinfo->objectid_information.out.guid, (ndr_pull_flags_fn_t)ndr_pull_GUID); for (i=0;i<6;i++) { fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8); } break; default: status = NT_STATUS_INVALID_INFO_CLASS; } failed: return status; }
/* recv a create reply */ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io) { NTSTATUS status; DATA_BLOB blob; int i; if (!smb2_request_receive(req) || !smb2_request_is_ok(req)) { return smb2_request_destroy(req); } SMB2_CHECK_PACKET_RECV(req, 0x58, true); ZERO_STRUCT(io->out); io->out.oplock_level = CVAL(req->in.body, 0x02); io->out.reserved = CVAL(req->in.body, 0x03); io->out.create_action = IVAL(req->in.body, 0x04); io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08); io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10); io->out.write_time = smbcli_pull_nttime(req->in.body, 0x18); io->out.change_time = smbcli_pull_nttime(req->in.body, 0x20); io->out.alloc_size = BVAL(req->in.body, 0x28); io->out.size = BVAL(req->in.body, 0x30); io->out.file_attr = IVAL(req->in.body, 0x38); io->out.reserved2 = IVAL(req->in.body, 0x3C); smb2_pull_handle(req->in.body+0x40, &io->out.file.handle); status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &blob); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } status = smb2_create_blob_parse(mem_ctx, blob, &io->out.blobs); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } /* pull out the parsed blobs */ for (i=0;i<io->out.blobs.num_blobs;i++) { if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) { /* TODO: this also contains a status field in first 4 bytes */ if (io->out.blobs.blobs[i].data.length != 8) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4); } if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) { if (io->out.blobs.blobs[i].data.length != 32) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32); } if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) { uint8_t *data; if (io->out.blobs.blobs[i].data.length != 32) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } data = io->out.blobs.blobs[i].data.data; memcpy(&io->out.lease_response.lease_key, data, 16); io->out.lease_response.lease_state = IVAL(data, 16); io->out.lease_response.lease_flags = IVAL(data, 20); io->out.lease_response.lease_duration = BVAL(data, 24); } } data_blob_free(&blob); return smb2_request_destroy(req); }