diff options
Diffstat (limited to 'source3/libsmb')
-rw-r--r-- | source3/libsmb/async_smb.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index b04c274b9d..24df6a600a 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -1095,3 +1095,130 @@ NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req, *plevel = state->level; return NT_STATUS_OK; } + + +struct cli_session_request_state { + struct tevent_context *ev; + int sock; + uint32 len_hdr; + struct iovec iov[3]; + uint8_t nb_session_response; +}; + +static void cli_session_request_sent(struct tevent_req *subreq); +static void cli_session_request_recvd(struct tevent_req *subreq); + +struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int sock, + const struct nmb_name *called, + const struct nmb_name *calling) +{ + struct tevent_req *req, *subreq; + struct cli_session_request_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct cli_session_request_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->sock = sock; + + state->iov[1].iov_base = name_mangle( + state, called->name, called->name_type); + if (tevent_req_nomem(state->iov[1].iov_base, req)) { + return tevent_req_post(req, ev); + } + state->iov[1].iov_len = name_len( + (unsigned char *)state->iov[1].iov_base, + talloc_get_size(state->iov[1].iov_base)); + + state->iov[2].iov_base = name_mangle( + state, calling->name, calling->name_type); + if (tevent_req_nomem(state->iov[2].iov_base, req)) { + return tevent_req_post(req, ev); + } + state->iov[2].iov_len = name_len( + (unsigned char *)state->iov[2].iov_base, + talloc_get_size(state->iov[2].iov_base)); + + _smb_setlen(((char *)&state->len_hdr), + state->iov[1].iov_len + state->iov[2].iov_len); + SCVAL((char *)&state->len_hdr, 0, 0x81); + + state->iov[0].iov_base = &state->len_hdr; + state->iov[0].iov_len = sizeof(state->len_hdr); + + subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_session_request_sent, req); + return req; +} + +static void cli_session_request_sent(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_session_request_state *state = tevent_req_data( + req, struct cli_session_request_state); + ssize_t ret; + int err; + + ret = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, err); + return; + } + subreq = read_smb_send(state, state->ev, state->sock); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_session_request_recvd, req); +} + +static void cli_session_request_recvd(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_session_request_state *state = tevent_req_data( + req, struct cli_session_request_state); + uint8_t *buf; + ssize_t ret; + int err; + + ret = read_smb_recv(subreq, talloc_tos(), &buf, &err); + TALLOC_FREE(subreq); + + if (ret < 4) { + ret = -1; + err = EIO; + } + if (ret == -1) { + tevent_req_error(req, err); + return; + } + /* + * In case of an error there is more information in the data + * portion according to RFC1002. We're not subtle enough to + * respond to the different error conditions, so drop the + * error info here. + */ + state->nb_session_response = CVAL(buf, 0); + tevent_req_done(req); +} + +bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp) +{ + struct cli_session_request_state *state = tevent_req_data( + req, struct cli_session_request_state); + + if (tevent_req_is_unix_error(req, err)) { + return false; + } + *resp = state->nb_session_response; + return true; +} |