static void smbd_smb2_read_pipe_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct smbd_smb2_read_state *state = tevent_req_data(req, struct smbd_smb2_read_state); NTSTATUS status; ssize_t nread = -1; bool is_data_outstanding; status = np_read_recv(subreq, &nread, &is_data_outstanding); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; } if (nread == 0 && state->out_data.length != 0) { tevent_req_nterror(req, NT_STATUS_END_OF_FILE); return; } state->out_data.length = nread; state->out_remaining = 0; /* * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also * handle it in SMB1 pipe_read_andx_done(). */ tevent_req_done(req); }
static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct smbd_smb2_ioctl_state *state = tevent_req_data(req, struct smbd_smb2_ioctl_state); NTSTATUS status; ssize_t nread = -1; bool is_data_outstanding = false; status = np_read_recv(subreq, &nread, &is_data_outstanding); DEBUG(10,("smbd_smb2_ioctl_pipe_read_done: np_read_recv nread = %d " "is_data_outstanding = %d, status = %s\n", (int)nread, (int)is_data_outstanding, nt_errstr(status) )); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; } state->out_output.length = nread; if (is_data_outstanding) { tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW); return; } tevent_req_done(req); }
struct tevent_req *smb2_ioctl_dfs(uint32_t ctl_code, struct tevent_context *ev, struct tevent_req *req, struct smbd_smb2_ioctl_state *state) { NTSTATUS status; switch (ctl_code) { case FSCTL_DFS_GET_REFERRALS: status = fsctl_dfs_get_refers(state, ev, state->smbreq->conn, &state->in_input, state->in_max_output, &state->out_output); if (!tevent_req_nterror(req, status)) { tevent_req_done(req); } return tevent_req_post(req, ev); break; default: { uint8_t *out_data = NULL; uint32_t out_data_len = 0; if (state->fsp == NULL) { status = NT_STATUS_NOT_SUPPORTED; } else { status = SMB_VFS_FSCTL(state->fsp, state, ctl_code, state->smbreq->flags2, state->in_input.data, state->in_input.length, &out_data, state->in_max_output, &out_data_len); state->out_output = data_blob_const(out_data, out_data_len); if (NT_STATUS_IS_OK(status)) { tevent_req_done(req); return tevent_req_post(req, ev); } } if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { if (IS_IPC(state->smbreq->conn)) { status = NT_STATUS_FS_DRIVER_REQUIRED; } else { status = NT_STATUS_INVALID_DEVICE_REQUEST; } } tevent_req_nterror(req, status); return tevent_req_post(req, ev); break; } } tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); return tevent_req_post(req, ev); }
static void open_socket_out_connected(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct open_socket_out_state *state = tevent_req_data(req, struct open_socket_out_state); int ret; int sys_errno; ret = async_connect_recv(subreq, &sys_errno); TALLOC_FREE(subreq); if (ret == 0) { tevent_req_done(req); return; } if ( #ifdef ETIMEDOUT (sys_errno == ETIMEDOUT) || #endif (sys_errno == EINPROGRESS) || (sys_errno == EALREADY) || (sys_errno == EAGAIN)) { /* * retry */ if (state->wait_usec < 250000) { state->wait_usec *= 1.5; } subreq = async_connect_send(state, state->ev, state->fd, (struct sockaddr *)&state->ss, state->salen); if (tevent_req_nomem(subreq, req)) { return; } if (!tevent_req_set_endtime( subreq, state->ev, timeval_current_ofs_usec(state->wait_usec))) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return; } tevent_req_set_callback(subreq, open_socket_out_connected, req); return; } #ifdef EISCONN if (sys_errno == EISCONN) { tevent_req_done(req); return; } #endif /* real error */ tevent_req_nterror(req, map_nt_error_from_unix(sys_errno)); }
static void wb_next_pwent_fill_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct wb_next_pwent_state *state = tevent_req_data( req, struct wb_next_pwent_state); NTSTATUS status; status = wb_fill_pwent_recv(subreq); TALLOC_FREE(subreq); /* * When you try to enumerate users with 'getent passwd' and the user * doesn't have a uid set we should just move on. */ if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { state->gstate->next_user += 1; if (state->gstate->next_user >= state->gstate->num_users) { TALLOC_FREE(state->gstate->users); state->gstate->domain = wb_next_find_domain(state->gstate->domain); if (state->gstate->domain == NULL) { tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); return; } subreq = wb_query_user_list_send(state, state->ev, state->gstate->domain); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, wb_next_pwent_fetch_done, req); return; } subreq = wb_fill_pwent_send(state, state->ev, &state->gstate->users[state->gstate->next_user], state->pw); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, wb_next_pwent_fill_done, req); return; } else if (tevent_req_nterror(req, status)) { return; } state->gstate->next_user += 1; tevent_req_done(req); }
static void smb2_ipc_getinfo(struct tevent_req *req, struct smbd_smb2_getinfo_state *state, struct tevent_context *ev, uint8_t in_info_type, uint8_t in_file_info_class) { /* We want to reply to SMB2_GETINFO_FILE with a class of SMB2_FILE_STANDARD_INFO as otherwise a Win7 client issues this request twice (2xroundtrips) if we return NOT_SUPPORTED. NB. We do the same for SMB1 in call_trans2qpipeinfo() */ if (in_info_type == 0x01 && /* SMB2_GETINFO_FILE */ in_file_info_class == 0x05) { /* SMB2_FILE_STANDARD_INFO */ state->out_output_buffer = data_blob_talloc(state, NULL, 24); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return; } memset(state->out_output_buffer.data,0,24); SOFF_T(state->out_output_buffer.data,0,4096LL); SIVAL(state->out_output_buffer.data,16,1); SIVAL(state->out_output_buffer.data,20,1); tevent_req_done(req); } else { tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); } }
static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct smbd_smb2_ioctl_state *state = tevent_req_data(req, struct smbd_smb2_ioctl_state); NTSTATUS status; ssize_t nwritten = -1; status = np_write_recv(subreq, &nwritten); DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: received %ld\n", (long int)nwritten )); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; } if (nwritten != state->in_input.length) { tevent_req_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE); return; } state->out_output = data_blob_talloc(state, NULL, state->in_max_output); if (state->in_max_output > 0 && tevent_req_nomem(state->out_output.data, req)) { return; } DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: issuing np_read_send " "of size %u\n", (unsigned int)state->out_output.length )); subreq = np_read_send(state->smbreq->conn, state->smb2req->sconn->ev_ctx, state->fsp->fake_file_handle, state->out_output.data, state->out_output.length); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_read_done, req); }
static void wb_next_pwent_fetch_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct wb_next_pwent_state *state = tevent_req_data( req, struct wb_next_pwent_state); NTSTATUS status; status = wb_query_user_list_recv(subreq, state->gstate, &state->gstate->num_users, &state->gstate->users); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { /* Ignore errors here, just log it */ DEBUG(10, ("query_user_list for domain %s returned %s\n", state->gstate->domain->name, nt_errstr(status))); state->gstate->num_users = 0; } if (state->gstate->num_users == 0) { state->gstate->domain = state->gstate->domain->next; if ((state->gstate->domain != NULL) && sid_check_is_domain(&state->gstate->domain->sid)) { state->gstate->domain = state->gstate->domain->next; } if (state->gstate->domain == NULL) { tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); return; } subreq = wb_query_user_list_send(state, state->ev, state->gstate->domain); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, wb_next_pwent_fetch_done, req); return; } state->gstate->next_user = 0; subreq = wb_fill_pwent_send( state, state->ev, &state->gstate->users[state->gstate->next_user], state->pw); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, wb_next_pwent_fill_done, req); }
void tevent_req_simple_finish_ntstatus(struct tevent_req *subreq, NTSTATUS subreq_status) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(subreq_status)) { tevent_req_nterror(req, subreq_status); return; } tevent_req_done(req); }
static void smbd_smb2_notify_reply_trigger(struct tevent_context *ctx, struct tevent_immediate *im, void *private_data) { struct tevent_req *req = talloc_get_type_abort(private_data, struct tevent_req); struct smbd_smb2_notify_state *state = tevent_req_data(req, struct smbd_smb2_notify_state); if (!NT_STATUS_IS_OK(state->status)) { tevent_req_nterror(req, state->status); return; } tevent_req_done(req); }
struct tevent_req *wb_next_pwent_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct getpwent_state *gstate, struct winbindd_pw *pw) { struct tevent_req *req, *subreq; struct wb_next_pwent_state *state; req = tevent_req_create(mem_ctx, &state, struct wb_next_pwent_state); if (req == NULL) { return NULL; } state->ev = ev; state->gstate = gstate; state->pw = pw; if (state->gstate->next_user >= state->gstate->num_users) { TALLOC_FREE(state->gstate->users); state->gstate->domain = wb_next_find_domain(state->gstate->domain); if (state->gstate->domain == NULL) { tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); return tevent_req_post(req, ev); } subreq = wb_query_user_list_send(state, state->ev, state->gstate->domain); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, wb_next_pwent_fetch_done, req); return req; } subreq = wb_fill_pwent_send( state, state->ev, &state->gstate->users[state->gstate->next_user], state->pw); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, wb_next_pwent_fill_done, req); return req; }
static void smbd_smb2_notify_reply(struct smb_request *smbreq, NTSTATUS error_code, uint8_t *buf, size_t len) { struct tevent_req *req = talloc_get_type_abort(smbreq->async_priv, struct tevent_req); struct smbd_smb2_notify_state *state = tevent_req_data(req, struct smbd_smb2_notify_state); if (state->skip_reply) { return; } SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(state->smb2req->profile); state->status = error_code; if (!NT_STATUS_IS_OK(error_code)) { /* nothing */ } else if (len == 0) { state->status = STATUS_NOTIFY_ENUM_DIR; } else { state->out_output_buffer = data_blob_talloc(state, buf, len); if (state->out_output_buffer.data == NULL) { state->status = NT_STATUS_NO_MEMORY; } } tevent_req_defer_callback(req, state->smb2req->sconn->ev_ctx); if (!NT_STATUS_IS_OK(state->status)) { tevent_req_nterror(req, state->status); return; } tevent_req_done(req); }
/* handle recv events on a cldap socket */ static void cldap_socket_recv_dgram(struct cldap_socket *c, struct cldap_incoming *in) { DATA_BLOB blob; struct asn1_data *asn1; void *p; struct cldap_search_state *search; NTSTATUS status; if (in->recv_errno != 0) { goto error; } blob = data_blob_const(in->buf, in->len); asn1 = asn1_init(in); if (!asn1) { goto nomem; } if (!asn1_load(asn1, blob)) { goto nomem; } in->ldap_msg = talloc(in, struct ldap_message); if (in->ldap_msg == NULL) { goto nomem; } /* this initial decode is used to find the message id */ status = ldap_decode(asn1, NULL, in->ldap_msg); if (!NT_STATUS_IS_OK(status)) { goto nterror; } /* find the pending request */ p = idr_find(c->searches.idr, in->ldap_msg->messageid); if (p == NULL) { if (!c->incoming.handler) { goto done; } /* this function should free or steal 'in' */ c->incoming.handler(c, c->incoming.private_data, in); return; } search = talloc_get_type(p, struct cldap_search_state); search->response.in = talloc_move(search, &in); search->response.asn1 = asn1; search->response.asn1->ofs = 0; tevent_req_done(search->req); goto done; nomem: in->recv_errno = ENOMEM; error: status = map_nt_error_from_unix(in->recv_errno); nterror: /* in connected mode the first pending search gets the error */ if (!c->connected) { /* otherwise we just ignore the error */ goto done; } if (!c->searches.list) { goto done; } tevent_req_nterror(c->searches.list->req, status); done: talloc_free(in); }
static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint16_t in_flags, uint32_t in_output_buffer_length, uint64_t in_completion_filter) { struct tevent_req *req; struct smbd_smb2_notify_state *state; struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat; bool recursive = (in_flags & SMB2_WATCH_TREE) ? true : false; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_notify_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->status = NT_STATUS_INTERNAL_ERROR; state->out_output_buffer = data_blob_null; talloc_set_destructor(state, smbd_smb2_notify_state_destructor); DEBUG(10,("smbd_smb2_notify_send: %s - %s\n", fsp_str_dbg(fsp), fsp_fnum_dbg(fsp))); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } state->smbreq = smbreq; smbreq->async_priv = (void *)req; if (DEBUGLEVEL >= 3) { char *filter_string; filter_string = notify_filter_string(NULL, in_completion_filter); if (tevent_req_nomem(filter_string, req)) { return tevent_req_post(req, ev); } DEBUG(3,("smbd_smb2_notify_send: notify change " "called on %s, filter = %s, recursive = %d\n", fsp_str_dbg(fsp), filter_string, recursive)); TALLOC_FREE(filter_string); } if ((!fsp->is_directory) || (conn != fsp->conn)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } if (fsp->notify == NULL) { status = change_notify_create(fsp, in_completion_filter, recursive); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("change_notify_create returned %s\n", nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } if (change_notify_fsp_has_changes(fsp)) { /* * We've got changes pending, respond immediately */ /* * TODO: write a torture test to check the filtering behaviour * here. */ change_notify_reply(smbreq, NT_STATUS_OK, in_output_buffer_length, fsp->notify, smbd_smb2_notify_reply); /* * change_notify_reply() above has independently * called tevent_req_done(). */ return tevent_req_post(req, ev); } /* * No changes pending, queue the request */ status = change_notify_add_request(smbreq, in_output_buffer_length, in_completion_filter, recursive, fsp, smbd_smb2_notify_reply); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return tevent_req_post(req, ev); } /* * This is a HACK! * * change_notify_add_request() talloc_moves() * smbreq away from us, so we need a destructor * which moves it back at the end. */ state->has_request = true; talloc_set_destructor(smbreq, smbd_smb2_notify_smbreq_destructor); /* allow this request to be canceled */ tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel); SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(state->smb2req->profile); return req; }
static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint32_t in_length, uint64_t in_offset, uint32_t in_minimum, uint32_t in_remaining) { NTSTATUS status; struct tevent_req *req = NULL; struct smbd_smb2_read_state *state = NULL; struct smb_request *smbreq = NULL; connection_struct *conn = smb2req->tcon->compat; ssize_t nread = -1; struct lock_struct lock; int saved_errno; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_read_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->in_length = in_length; state->in_offset = in_offset; state->in_minimum = in_minimum; state->out_data = data_blob_null; state->out_remaining = 0; DEBUG(10,("smbd_smb2_read: %s - %s\n", fsp_str_dbg(fsp), fsp_fnum_dbg(fsp))); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } state->smbreq = smbreq; if (fsp->is_directory) { tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); return tevent_req_post(req, ev); } state->fsp = fsp; if (IS_IPC(smbreq->conn)) { struct tevent_req *subreq = NULL; state->out_data = data_blob_talloc(state, NULL, in_length); if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { return tevent_req_post(req, ev); } if (!fsp_is_np(fsp)) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } subreq = np_read_send(state, ev, fsp->fake_file_handle, state->out_data.data, state->out_data.length); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, smbd_smb2_read_pipe_done, req); return req; } if (!CHECK_READ(fsp, smbreq)) { tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); return tevent_req_post(req, ev); } status = schedule_smb2_aio_read(fsp->conn, smbreq, fsp, state, &state->out_data, (off_t)in_offset, (size_t)in_length); if (NT_STATUS_IS_OK(status)) { /* * Doing an async read, allow this * request to be canceled */ tevent_req_set_cancel_fn(req, smbd_smb2_read_cancel); return req; } if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { /* Real error in setting up aio. Fail. */ tevent_req_nterror(req, status); return tevent_req_post(req, ev); } /* Fallback to synchronous. */ init_strict_lock_struct(fsp, fsp->op->global->open_persistent_id, in_offset, in_length, READ_LOCK, &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); return tevent_req_post(req, ev); } /* Try sendfile in preference. */ status = schedule_smb2_sendfile_read(smb2req, state); if (NT_STATUS_IS_OK(status)) { tevent_req_done(req); return tevent_req_post(req, ev); } else { if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } /* Ok, read into memory. Allocate the out buffer. */ state->out_data = data_blob_talloc(state, NULL, in_length); if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); return tevent_req_post(req, ev); } nread = read_file(fsp, (char *)state->out_data.data, in_offset, in_length); saved_errno = errno; SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); DEBUG(10,("smbd_smb2_read: file %s, %s, offset=%llu " "len=%llu returned %lld\n", fsp_str_dbg(fsp), fsp_fnum_dbg(fsp), (unsigned long long)in_offset, (unsigned long long)in_length, (long long)nread)); status = smb2_read_complete(req, nread, saved_errno); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); } else { /* Success. */ tevent_req_done(req); } return tevent_req_post(req, ev); }
static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, uint32_t in_smbpid, uint64_t in_file_id_volatile, uint32_t in_length, uint64_t in_offset, uint32_t in_minimum, uint32_t in_remaining) { NTSTATUS status; struct tevent_req *req = NULL; struct smbd_smb2_read_state *state = NULL; struct smb_request *smbreq = NULL; connection_struct *conn = smb2req->tcon->compat_conn; files_struct *fsp = NULL; ssize_t nread = -1; struct lock_struct lock; int saved_errno; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_read_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->in_length = in_length; state->in_offset = in_offset; state->in_minimum = in_minimum; state->out_data = data_blob_null; state->out_remaining = 0; DEBUG(10,("smbd_smb2_read: file_id[0x%016llX]\n", (unsigned long long)in_file_id_volatile)); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); if (fsp == NULL) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } if (conn != fsp->conn) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } if (smb2req->session->vuid != fsp->vuid) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } if (fsp->is_directory) { tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); return tevent_req_post(req, ev); } state->fsp = fsp; state->in_file_id_volatile = in_file_id_volatile; if (IS_IPC(smbreq->conn)) { struct tevent_req *subreq = NULL; state->out_data = data_blob_talloc(state, NULL, in_length); if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { return tevent_req_post(req, ev); } if (!fsp_is_np(fsp)) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } subreq = np_read_send(state, server_event_context(), fsp->fake_file_handle, state->out_data.data, state->out_data.length); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, smbd_smb2_read_pipe_done, req); return req; } if (!CHECK_READ(fsp, smbreq)) { tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); return tevent_req_post(req, ev); } status = schedule_smb2_aio_read(fsp->conn, smbreq, fsp, state, &state->out_data, (SMB_OFF_T)in_offset, (size_t)in_length); if (NT_STATUS_IS_OK(status)) { /* * Doing an async read. Don't * send a "gone async" message * as we expect this to be less * than the client timeout period. * JRA. FIXME for offline files.. * FIXME. Add cancel code.. */ smb2req->async = true; return req; } if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { /* Real error in setting up aio. Fail. */ tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } /* Fallback to synchronous. */ init_strict_lock_struct(fsp, in_file_id_volatile, in_offset, in_length, READ_LOCK, &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); return tevent_req_post(req, ev); } /* Try sendfile in preference. */ status = schedule_smb2_sendfile_read(smb2req, state); if (NT_STATUS_IS_OK(status)) { tevent_req_done(req); return tevent_req_post(req, ev); } else { if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } /* Ok, read into memory. Allocate the out buffer. */ state->out_data = data_blob_talloc(state, NULL, in_length); if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); return tevent_req_post(req, ev); } nread = read_file(fsp, (char *)state->out_data.data, in_offset, in_length); saved_errno = errno; SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); DEBUG(10,("smbd_smb2_read: file %s handle [0x%016llX] offset=%llu " "len=%llu returned %lld\n", fsp_str_dbg(fsp), (unsigned long long)in_file_id_volatile, (unsigned long long)in_offset, (unsigned long long)in_length, (long long)nread)); status = smb2_read_complete(req, nread, saved_errno); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); } else { /* Success. */ tevent_req_done(req); } return tevent_req_post(req, ev); }
struct tevent_req *smb2_ioctl_named_pipe(uint32_t ctl_code, struct tevent_context *ev, struct tevent_req *req, struct smbd_smb2_ioctl_state *state) { NTSTATUS status; uint8_t *out_data = NULL; uint32_t out_data_len = 0; if (ctl_code == FSCTL_PIPE_TRANSCEIVE) { struct tevent_req *subreq; if (!IS_IPC(state->smbreq->conn)) { tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); return tevent_req_post(req, ev); } if (state->fsp == NULL) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } if (!fsp_is_np(state->fsp)) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev); } DEBUG(10,("smbd_smb2_ioctl_send: np_write_send of size %u\n", (unsigned int)state->in_input.length )); subreq = np_write_send(state, ev, state->fsp->fake_file_handle, state->in_input.data, state->in_input.length); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_write_done, req); return req; } if (state->fsp == NULL) { status = NT_STATUS_NOT_SUPPORTED; } else { status = SMB_VFS_FSCTL(state->fsp, state, ctl_code, state->smbreq->flags2, state->in_input.data, state->in_input.length, &out_data, state->in_max_output, &out_data_len); state->out_output = data_blob_const(out_data, out_data_len); if (NT_STATUS_IS_OK(status)) { tevent_req_done(req); return tevent_req_post(req, ev); } } if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { if (IS_IPC(state->smbreq->conn)) { status = NT_STATUS_FS_DRIVER_REQUIRED; } else { status = NT_STATUS_INVALID_DEVICE_REQUEST; } } tevent_req_nterror(req, status); return tevent_req_post(req, ev); }
struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx, struct event_context *ev, const struct sockaddr_storage *pss, uint16_t port, int timeout) { char addr[INET6_ADDRSTRLEN]; struct tevent_req *result, *subreq; struct open_socket_out_state *state; NTSTATUS status; result = tevent_req_create(mem_ctx, &state, struct open_socket_out_state); if (result == NULL) { return NULL; } state->ev = ev; state->ss = *pss; state->port = port; state->wait_usec = 10000; state->salen = -1; state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0); if (state->fd == -1) { status = map_nt_error_from_unix(errno); goto post_status; } talloc_set_destructor(state, open_socket_out_state_destructor); if (!tevent_req_set_endtime( result, ev, timeval_current_ofs_msec(timeout))) { goto fail; } #if defined(HAVE_IPV6) if (pss->ss_family == AF_INET6) { struct sockaddr_in6 *psa6; psa6 = (struct sockaddr_in6 *)&state->ss; psa6->sin6_port = htons(port); if (psa6->sin6_scope_id == 0 && IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) { setup_linklocal_scope_id( (struct sockaddr *)&(state->ss)); } state->salen = sizeof(struct sockaddr_in6); } #endif if (pss->ss_family == AF_INET) { struct sockaddr_in *psa; psa = (struct sockaddr_in *)&state->ss; psa->sin_port = htons(port); state->salen = sizeof(struct sockaddr_in); } if (pss->ss_family == AF_UNIX) { state->salen = sizeof(struct sockaddr_un); } print_sockaddr(addr, sizeof(addr), &state->ss); DEBUG(3,("Connecting to %s at port %u\n", addr, (unsigned int)port)); subreq = async_connect_send(state, state->ev, state->fd, (struct sockaddr *)&state->ss, state->salen); if ((subreq == NULL) || !tevent_req_set_endtime( subreq, state->ev, timeval_current_ofs(0, state->wait_usec))) { goto fail; } tevent_req_set_callback(subreq, open_socket_out_connected, result); return result; post_status: tevent_req_nterror(result, status); return tevent_req_post(result, ev); fail: TALLOC_FREE(result); return NULL; }
static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint16_t in_flags, uint32_t in_output_buffer_length, uint64_t in_completion_filter) { struct tevent_req *req; struct smbd_smb2_notify_state *state; struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat_conn; bool recursive = (in_flags & 0x0001) ? true : false; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_notify_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->status = NT_STATUS_INTERNAL_ERROR; state->out_output_buffer = data_blob_null; state->im = NULL; DEBUG(10,("smbd_smb2_notify_send: %s - fnum[%d]\n", fsp_str_dbg(fsp), fsp->fnum)); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } state->smbreq = smbreq; smbreq->async_priv = (void *)req; { char *filter_string; filter_string = notify_filter_string(NULL, in_completion_filter); if (tevent_req_nomem(filter_string, req)) { return tevent_req_post(req, ev); } DEBUG(3,("smbd_smb2_notify_send: notify change " "called on %s, filter = %s, recursive = %d\n", fsp_str_dbg(fsp), filter_string, recursive)); TALLOC_FREE(filter_string); } if ((!fsp->is_directory) || (conn != fsp->conn)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } if (fsp->notify == NULL) { status = change_notify_create(fsp, in_completion_filter, recursive); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("change_notify_create returned %s\n", nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } if (fsp->notify->num_changes != 0) { /* * We've got changes pending, respond immediately */ /* * TODO: write a torture test to check the filtering behaviour * here. */ change_notify_reply(smbreq, NT_STATUS_OK, in_output_buffer_length, fsp->notify, smbd_smb2_notify_reply); /* * change_notify_reply() above has independently * called tevent_req_done(). */ return tevent_req_post(req, ev); } state->im = tevent_create_immediate(state); if (tevent_req_nomem(state->im, req)) { return tevent_req_post(req, ev); } /* * No changes pending, queue the request */ status = change_notify_add_request(smbreq, in_output_buffer_length, in_completion_filter, recursive, fsp, smbd_smb2_notify_reply); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return tevent_req_post(req, ev); } /* allow this request to be canceled */ tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel); return req; }
/* handle recv events on a cldap socket */ static bool cldap_socket_recv_dgram(struct cldap_socket *c, struct cldap_incoming *in) { DATA_BLOB blob; struct asn1_data *asn1; void *p; struct cldap_search_state *search; NTSTATUS status; if (in->recv_errno != 0) { goto error; } blob = data_blob_const(in->buf, in->len); asn1 = asn1_init(in); if (!asn1) { goto nomem; } if (!asn1_load(asn1, blob)) { goto nomem; } in->ldap_msg = talloc(in, struct ldap_message); if (in->ldap_msg == NULL) { goto nomem; } /* this initial decode is used to find the message id */ status = ldap_decode(asn1, NULL, in->ldap_msg); if (!NT_STATUS_IS_OK(status)) { goto nterror; } /* find the pending request */ p = idr_find(c->searches.idr, in->ldap_msg->messageid); if (p == NULL) { if (!c->incoming.handler) { TALLOC_FREE(in); return true; } /* this function should free or steal 'in' */ c->incoming.handler(c, c->incoming.private_data, in); return false; } search = talloc_get_type_abort(p, struct cldap_search_state); search->response.in = talloc_move(search, &in); search->response.asn1 = asn1; search->response.asn1->ofs = 0; DLIST_REMOVE(c->searches.list, search); if (cldap_recvfrom_setup(c)) { tevent_req_done(search->req); return true; } /* * This request was ok, just defer the notify of the caller * and then just fail the next request if needed */ tevent_req_defer_callback(search->req, search->caller.ev); tevent_req_done(search->req); status = NT_STATUS_NO_MEMORY; /* in is NULL it this point */ goto nterror; nomem: in->recv_errno = ENOMEM; error: status = map_nt_error_from_unix_common(in->recv_errno); nterror: TALLOC_FREE(in); /* in connected mode the first pending search gets the error */ if (!c->connected) { /* otherwise we just ignore the error */ return false; } if (!c->searches.list) { return false; } /* * We might called tevent_req_done() for a successful * search before, so we better deliver the failure * after the success, that is why we better also * use tevent_req_defer_callback() here. */ tevent_req_defer_callback(c->searches.list->req, c->searches.list->caller.ev); tevent_req_nterror(c->searches.list->req, status); return false; }
static void cli_trans_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct cli_trans_state *state = tevent_req_data( req, struct cli_trans_state); NTSTATUS status; bool sent_all; uint8_t wct; uint16_t *vwv; uint32_t num_bytes; uint8_t *bytes; uint8_t num_setup = 0; uint16_t *setup = NULL; uint32_t total_param = 0; uint32_t num_param = 0; uint32_t param_disp = 0; uint32_t total_data = 0; uint32_t num_data = 0; uint32_t data_disp = 0; uint8_t *param = NULL; uint8_t *data = NULL; status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes); /* * We can receive something like STATUS_MORE_ENTRIES, so don't use * !NT_STATUS_IS_OK(status) here. */ if (NT_STATUS_IS_ERR(status)) { goto fail; } sent_all = ((state->param_sent == state->num_param) && (state->data_sent == state->num_data)); status = cli_pull_trans( cli_smb_inbuf(subreq), wct, vwv, num_bytes, bytes, state->cmd, !sent_all, &num_setup, &setup, &total_param, &num_param, ¶m_disp, ¶m, &total_data, &num_data, &data_disp, &data); if (!NT_STATUS_IS_OK(status)) { goto fail; } if (!sent_all) { int iov_count; TALLOC_FREE(subreq); cli_trans_format(state, &wct, &iov_count); subreq = cli_smb_req_create(state, state->ev, state->cli, state->cmd + 1, 0, wct, state->vwv, iov_count, state->iov); if (tevent_req_nomem(subreq, req)) { return; } cli_smb_req_set_mid(subreq, state->mid); if (!cli_smb_req_send(subreq)) { status = NT_STATUS_NO_MEMORY; goto fail; } tevent_req_set_callback(subreq, cli_trans_done, req); return; } status = cli_trans_pull_blob( state, &state->rparam, total_param, num_param, param, param_disp); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status))); goto fail; } status = cli_trans_pull_blob( state, &state->rdata, total_data, num_data, data, data_disp); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status))); goto fail; } if ((state->rparam.total == state->rparam.received) && (state->rdata.total == state->rdata.received)) { TALLOC_FREE(subreq); cli_state_seqnum_remove(state->cli, state->mid); tevent_req_done(req); return; } if (!cli_smb_req_set_pending(subreq)) { status = NT_STATUS_NO_MEMORY; goto fail; } return; fail: cli_state_seqnum_remove(state->cli, state->mid); TALLOC_FREE(subreq); tevent_req_nterror(req, status); }
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint8_t in_info_type, uint8_t in_file_info_class, uint32_t in_output_buffer_length, DATA_BLOB in_input_buffer, uint32_t in_additional_information, uint32_t in_flags) { struct tevent_req *req; struct smbd_smb2_getinfo_state *state; struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_getinfo_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->status = NT_STATUS_OK; state->out_output_buffer = data_blob_null; DEBUG(10,("smbd_smb2_getinfo_send: %s - %s\n", fsp_str_dbg(fsp), fsp_fnum_dbg(fsp))); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } if (IS_IPC(conn)) { smb2_ipc_getinfo(req, state, ev, in_info_type, in_file_info_class); return tevent_req_post(req, ev); } switch (in_info_type) { case SMB2_GETINFO_FILE: { uint16_t file_info_level; char *data = NULL; unsigned int data_size = 0; bool delete_pending = false; struct timespec write_time_ts; struct file_id fileid; struct ea_list *ea_list = NULL; int lock_data_count = 0; char *lock_data = NULL; size_t fixed_portion; ZERO_STRUCT(write_time_ts); switch (in_file_info_class) { case 0x0F:/* RAW_FILEINFO_SMB2_ALL_EAS */ file_info_level = 0xFF00 | in_file_info_class; break; case 0x12:/* RAW_FILEINFO_SMB2_ALL_INFORMATION */ file_info_level = 0xFF00 | in_file_info_class; break; default: /* the levels directly map to the passthru levels */ file_info_level = in_file_info_class + 1000; break; } if (fsp->fake_file_handle) { /* * This is actually for the QUOTA_FAKE_FILE --metze */ /* We know this name is ok, it's already passed the checks. */ } else if (fsp->fh->fd == -1) { /* * This is actually a QFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems * to do this call. JRA. */ if (INFO_LEVEL_IS_UNIX(file_info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) { DEBUG(3,("smbd_smb2_getinfo_send: " "SMB_VFS_LSTAT of %s failed " "(%s)\n", fsp_str_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } else if (SMB_VFS_STAT(conn, fsp->fsp_name)) { DEBUG(3,("smbd_smb2_getinfo_send: " "SMB_VFS_STAT of %s failed (%s)\n", fsp_str_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } fileid = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); get_file_infos(fileid, fsp->name_hash, &delete_pending, &write_time_ts); } else { /* * Original code - this is an open file. */ if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { DEBUG(3, ("smbd_smb2_getinfo_send: " "fstat of %s failed (%s)\n", fsp_fnum_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } fileid = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); get_file_infos(fileid, fsp->name_hash, &delete_pending, &write_time_ts); } status = smbd_do_qfilepathinfo(conn, state, file_info_level, fsp, fsp->fsp_name, delete_pending, write_time_ts, ea_list, lock_data_count, lock_data, STR_UNICODE, in_output_buffer_length, &fixed_portion, &data, &data_size); if (!NT_STATUS_IS_OK(status)) { SAFE_FREE(data); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { status = NT_STATUS_INVALID_INFO_CLASS; } tevent_req_nterror(req, status); return tevent_req_post(req, ev); } if (in_output_buffer_length < fixed_portion) { SAFE_FREE(data); tevent_req_nterror( req, NT_STATUS_INFO_LENGTH_MISMATCH); return tevent_req_post(req, ev); } if (data_size > 0) { state->out_output_buffer = data_blob_talloc(state, data, data_size); SAFE_FREE(data); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } if (data_size > in_output_buffer_length) { state->out_output_buffer.length = in_output_buffer_length; status = STATUS_BUFFER_OVERFLOW; } } SAFE_FREE(data); break; } case SMB2_GETINFO_FS: { uint16_t file_info_level; char *data = NULL; int data_size = 0; size_t fixed_portion; /* the levels directly map to the passthru levels */ file_info_level = in_file_info_class + 1000; status = smbd_do_qfsinfo(conn, state, file_info_level, STR_UNICODE, in_output_buffer_length, &fixed_portion, fsp->fsp_name, &data, &data_size); /* some responses set STATUS_BUFFER_OVERFLOW and return partial, but valid data */ if (!(NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW))) { SAFE_FREE(data); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { status = NT_STATUS_INVALID_INFO_CLASS; } tevent_req_nterror(req, status); return tevent_req_post(req, ev); } if (in_output_buffer_length < fixed_portion) { SAFE_FREE(data); tevent_req_nterror( req, NT_STATUS_INFO_LENGTH_MISMATCH); return tevent_req_post(req, ev); } if (data_size > 0) { state->out_output_buffer = data_blob_talloc(state, data, data_size); SAFE_FREE(data); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } if (data_size > in_output_buffer_length) { state->out_output_buffer.length = in_output_buffer_length; status = STATUS_BUFFER_OVERFLOW; } } SAFE_FREE(data); break; } case SMB2_GETINFO_SECURITY: { uint8_t *p_marshalled_sd = NULL; size_t sd_size = 0; status = smbd_do_query_security_desc(conn, state, fsp, /* Security info wanted. */ in_additional_information & SMB_SUPPORTED_SECINFO_FLAGS, in_output_buffer_length, &p_marshalled_sd, &sd_size); if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { /* Return needed size. */ state->out_output_buffer = data_blob_talloc(state, NULL, 4); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } SIVAL(state->out_output_buffer.data,0,(uint32_t)sd_size); state->status = NT_STATUS_BUFFER_TOO_SMALL; break; } if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("smbd_smb2_getinfo_send: " "smbd_do_query_security_desc of %s failed " "(%s)\n", fsp_str_dbg(fsp), nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } if (sd_size > 0) { state->out_output_buffer = data_blob_talloc(state, p_marshalled_sd, sd_size); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } } break; } case SMB2_GETINFO_QUOTA: tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); return tevent_req_post(req, ev); default: DEBUG(10,("smbd_smb2_getinfo_send: " "unknown in_info_type of %u " " for file %s\n", (unsigned int)in_info_type, fsp_str_dbg(fsp) )); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } state->status = status; tevent_req_done(req); return tevent_req_post(req, ev); }
static void smb1cli_trans_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct smb1cli_trans_state *state = tevent_req_data(req, struct smb1cli_trans_state); NTSTATUS status; bool sent_all; struct iovec *recv_iov = NULL; uint8_t *inhdr; uint8_t wct; uint16_t *vwv; uint32_t vwv_ofs; uint32_t num_bytes; uint8_t *bytes; uint32_t bytes_ofs; uint8_t num_setup = 0; uint16_t *setup = NULL; uint32_t total_param = 0; uint32_t num_param = 0; uint32_t param_disp = 0; uint32_t total_data = 0; uint32_t num_data = 0; uint32_t data_disp = 0; uint8_t *param = NULL; uint8_t *data = NULL; status = smb1cli_req_recv(subreq, state, &recv_iov, &inhdr, &wct, &vwv, &vwv_ofs, &num_bytes, &bytes, &bytes_ofs, NULL, /* pinbuf */ NULL, 0); /* expected */ /* * Do not TALLOC_FREE(subreq) here, we might receive more than * one response for the same mid. */ /* * We can receive something like STATUS_MORE_ENTRIES, so don't use * !NT_STATUS_IS_OK(status) here. */ if (NT_STATUS_IS_ERR(status)) { goto fail; } if (recv_iov == NULL) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto fail; } state->status = status; sent_all = ((state->param_sent == state->num_param) && (state->data_sent == state->num_data)); status = smb1cli_pull_trans( inhdr, wct, vwv, vwv_ofs, num_bytes, bytes, bytes_ofs, state->cmd, !sent_all, &num_setup, &setup, &total_param, &num_param, ¶m_disp, ¶m, &total_data, &num_data, &data_disp, &data); if (!NT_STATUS_IS_OK(status)) { goto fail; } if (!sent_all) { int iov_count; struct tevent_req *subreq2; smb1cli_trans_format(state, &wct, &iov_count); subreq2 = smb1cli_req_create(state, state->ev, state->conn, state->cmd + 1, state->additional_flags, state->clear_flags, state->additional_flags2, state->clear_flags2, state->timeout_msec, state->pid, state->tid, state->uid, wct, state->vwv, iov_count, state->iov); if (tevent_req_nomem(subreq2, req)) { return; } smb1cli_req_set_mid(subreq2, state->mid); status = smb1cli_req_chain_submit(&subreq2, 1); if (!NT_STATUS_IS_OK(status)) { goto fail; } tevent_req_set_callback(subreq2, smb1cli_trans_done2, req); return; } status = smb1cli_trans_pull_blob( state, &state->rparam, total_param, num_param, param, param_disp); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status))); goto fail; } status = smb1cli_trans_pull_blob( state, &state->rdata, total_data, num_data, data, data_disp); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status))); goto fail; } if ((state->rparam.total == state->rparam.received) && (state->rdata.total == state->rdata.received)) { state->recv_flags2 = SVAL(inhdr, HDR_FLG2); smb1cli_trans_cleanup_primary(state); tevent_req_done(req); return; } TALLOC_FREE(recv_iov); return; fail: smb1cli_trans_cleanup_primary(state); tevent_req_nterror(req, status); }
struct tevent_req *smb1cli_trans_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbXcli_conn *conn, uint8_t cmd, uint8_t additional_flags, uint8_t clear_flags, uint16_t additional_flags2, uint16_t clear_flags2, uint32_t timeout_msec, uint32_t pid, uint16_t tid, uint16_t uid, const char *pipe_name, uint16_t fid, uint16_t function, int flags, uint16_t *setup, uint8_t num_setup, uint8_t max_setup, uint8_t *param, uint32_t num_param, uint32_t max_param, uint8_t *data, uint32_t num_data, uint32_t max_data) { struct tevent_req *req, *subreq; struct smb1cli_trans_state *state; int iov_count; uint8_t wct; NTSTATUS status; charset_t charset; req = tevent_req_create(mem_ctx, &state, struct smb1cli_trans_state); if (req == NULL) { return NULL; } if ((cmd == SMBtrans) || (cmd == SMBtrans2)) { if ((num_param > 0xffff) || (max_param > 0xffff) || (num_data > 0xffff) || (max_data > 0xffff)) { DEBUG(3, ("Attempt to send invalid trans2 request " "(setup %u, params %u/%u, data %u/%u)\n", (unsigned)num_setup, (unsigned)num_param, (unsigned)max_param, (unsigned)num_data, (unsigned)max_data)); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); return tevent_req_post(req, ev); } } /* * The largest wct will be for nttrans (19+num_setup). Make sure we * don't overflow state->vwv in smb1cli_trans_format. */ if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); return tevent_req_post(req, ev); } state->conn = conn; state->ev = ev; state->cmd = cmd; state->additional_flags = additional_flags; state->clear_flags = clear_flags; state->additional_flags2 = additional_flags2; state->clear_flags2 = clear_flags2; state->timeout_msec = timeout_msec; state->flags = flags; state->num_rsetup = 0; state->rsetup = NULL; state->pid = pid; state->tid = tid; state->uid = uid; ZERO_STRUCT(state->rparam); ZERO_STRUCT(state->rdata); if (smbXcli_conn_use_unicode(conn)) { charset = CH_UTF16LE; } else { charset = CH_DOS; } if ((pipe_name != NULL) && (!convert_string_talloc(state, CH_UNIX, charset, pipe_name, strlen(pipe_name) + 1, &state->pipe_name_conv, &state->pipe_name_conv_len))) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return tevent_req_post(req, ev); } state->fid = fid; /* trans2 */ state->function = function; /* nttrans */ state->setup = setup; state->num_setup = num_setup; state->max_setup = max_setup; state->param = param; state->num_param = num_param; state->param_sent = 0; state->rparam.max = max_param; state->data = data; state->num_data = num_data; state->data_sent = 0; state->rdata.max = max_data; smb1cli_trans_format(state, &wct, &iov_count); subreq = smb1cli_req_create(state, ev, conn, cmd, state->additional_flags, state->clear_flags, state->additional_flags2, state->clear_flags2, state->timeout_msec, state->pid, state->tid, state->uid, wct, state->vwv, iov_count, state->iov); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } status = smb1cli_req_chain_submit(&subreq, 1); if (tevent_req_nterror(req, status)) { return tevent_req_post(req, state->ev); } tevent_req_set_callback(subreq, smb1cli_trans_done, req); /* * Now get the MID of the primary request * and mark it as persistent. This means * we will able to send and receive multiple * SMB pdus using this MID in both directions * (including correct SMB signing). */ state->mid = smb1cli_req_mid(subreq); smb1cli_req_set_mid(subreq, state->mid); state->primary_subreq = subreq; talloc_set_destructor(state, smb1cli_trans_state_destructor); tevent_req_set_cancel_fn(req, smb1cli_trans_cancel); return req; }
struct tevent_req *cli_trans_send( TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, uint8_t cmd, const char *pipe_name, uint16_t fid, uint16_t function, int flags, uint16_t *setup, uint8_t num_setup, uint8_t max_setup, uint8_t *param, uint32_t num_param, uint32_t max_param, uint8_t *data, uint32_t num_data, uint32_t max_data) { struct tevent_req *req, *subreq; struct cli_trans_state *state; int iov_count; uint8_t wct; req = tevent_req_create(mem_ctx, &state, struct cli_trans_state); if (req == NULL) { return NULL; } if ((cmd == SMBtrans) || (cmd == SMBtrans2)) { if ((num_param > 0xffff) || (max_param > 0xffff) || (num_data > 0xffff) || (max_data > 0xffff)) { DEBUG(3, ("Attempt to send invalid trans2 request " "(setup %u, params %u/%u, data %u/%u)\n", (unsigned)num_setup, (unsigned)num_param, (unsigned)max_param, (unsigned)num_data, (unsigned)max_data)); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } } /* * The largest wct will be for nttrans (19+num_setup). Make sure we * don't overflow state->vwv in cli_trans_format. */ if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } state->cli = cli; state->ev = ev; state->cmd = cmd; state->flags = flags; state->num_rsetup = 0; state->rsetup = NULL; ZERO_STRUCT(state->rparam); ZERO_STRUCT(state->rdata); if ((pipe_name != NULL) && (!convert_string_talloc(state, CH_UNIX, cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, pipe_name, strlen(pipe_name) + 1, &state->pipe_name_conv, &state->pipe_name_conv_len, true))) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return tevent_req_post(req, ev); } state->fid = fid; /* trans2 */ state->function = function; /* nttrans */ state->setup = setup; state->num_setup = num_setup; state->max_setup = max_setup; state->param = param; state->num_param = num_param; state->param_sent = 0; state->rparam.max = max_param; state->data = data; state->num_data = num_data; state->data_sent = 0; state->rdata.max = max_data; cli_trans_format(state, &wct, &iov_count); subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv, iov_count, state->iov); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } state->mid = cli_smb_req_mid(subreq); if (!cli_smb_req_send(subreq)) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return tevent_req_post(req, state->ev); } cli_state_seqnum_persistent(cli, state->mid); tevent_req_set_callback(subreq, cli_trans_done, req); return req; }
static void smb1cli_trans_done2(struct tevent_req *subreq2) { struct tevent_req *req = tevent_req_callback_data(subreq2, struct tevent_req); struct smb1cli_trans_state *state = tevent_req_data(req, struct smb1cli_trans_state); NTSTATUS status; bool sent_all; uint32_t seqnum; /* * First backup the seqnum of the secondary request * and attach it to the primary request. */ seqnum = smb1cli_req_seqnum(subreq2); smb1cli_req_set_seqnum(state->primary_subreq, seqnum); /* This was a one way request */ status = smb1cli_req_recv(subreq2, state, NULL, /* recv_iov */ NULL, /* phdr */ NULL, /* pwct */ NULL, /* pvwv */ NULL, /* pvwv_offset */ NULL, /* pnum_bytes */ NULL, /* pbytes */ NULL, /* pbytes_offset */ NULL, /* pinbuf */ NULL, 0); /* expected */ TALLOC_FREE(subreq2); if (!NT_STATUS_IS_OK(status)) { goto fail; } sent_all = ((state->param_sent == state->num_param) && (state->data_sent == state->num_data)); if (!sent_all) { uint8_t wct; int iov_count; smb1cli_trans_format(state, &wct, &iov_count); subreq2 = smb1cli_req_create(state, state->ev, state->conn, state->cmd + 1, state->additional_flags, state->clear_flags, state->additional_flags2, state->clear_flags2, state->timeout_msec, state->pid, state->tid, state->uid, wct, state->vwv, iov_count, state->iov); if (tevent_req_nomem(subreq2, req)) { return; } smb1cli_req_set_mid(subreq2, state->mid); status = smb1cli_req_chain_submit(&subreq2, 1); if (!NT_STATUS_IS_OK(status)) { goto fail; } tevent_req_set_callback(subreq2, smb1cli_trans_done2, req); return; } return; fail: smb1cli_trans_cleanup_primary(state); tevent_req_nterror(req, status); }
static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint32_t in_ctl_code, DATA_BLOB in_input, uint32_t in_max_output, uint32_t in_flags) { struct tevent_req *req; struct smbd_smb2_ioctl_state *state; struct smb_request *smbreq; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_ioctl_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->smbreq = NULL; state->fsp = fsp; state->in_input = in_input; state->in_max_output = in_max_output; state->out_output = data_blob_null; DEBUG(10, ("smbd_smb2_ioctl: ctl_code[0x%08x] %s, %s\n", (unsigned)in_ctl_code, fsp ? fsp_str_dbg(fsp) : "<no handle>", fsp_fnum_dbg(fsp))); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } state->smbreq = smbreq; switch (in_ctl_code & IOCTL_DEV_TYPE_MASK) { case FSCTL_DFS: return smb2_ioctl_dfs(in_ctl_code, ev, req, state); break; case FSCTL_FILESYSTEM: return smb2_ioctl_filesys(in_ctl_code, ev, req, state); break; case FSCTL_NAMED_PIPE: return smb2_ioctl_named_pipe(in_ctl_code, ev, req, state); break; case FSCTL_NETWORK_FILESYSTEM: return smb2_ioctl_network_fs(in_ctl_code, ev, req, state); break; default: if (IS_IPC(smbreq->conn)) { tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED); } else { tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); } return tevent_req_post(req, ev); break; } tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); return tevent_req_post(req, ev); }