pidl/NDR/Parser: do array range validation in ParseArrayPullGetLength()
[Samba.git] / source3 / rpc_client / rpc_transport_sock.c
blob442f3099e1f0ec116a03d76a8da9247922d2febf
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC client transport over a socket
4 * Copyright (C) Volker Lendecke 2009
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
22 #undef DBGC_CLASS
23 #define DBGC_CLASS DBGC_RPC_CLI
25 struct rpc_transport_sock_state {
26 int fd;
27 int timeout;
30 static void rpc_sock_disconnect(struct rpc_transport_sock_state *s)
32 if (s->fd != -1) {
33 close(s->fd);
34 s->fd = -1;
38 static int rpc_transport_sock_state_destructor(struct rpc_transport_sock_state *s)
40 rpc_sock_disconnect(s);
41 return 0;
44 static bool rpc_sock_is_connected(void *priv)
46 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
47 priv, struct rpc_transport_sock_state);
49 if (sock_transp->fd == -1) {
50 return false;
53 return true;
56 static unsigned int rpc_sock_set_timeout(void *priv, unsigned int timeout)
58 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
59 priv, struct rpc_transport_sock_state);
60 int orig_timeout;
61 bool ok;
63 ok = rpc_sock_is_connected(sock_transp);
64 if (!ok) {
65 return 0;
68 orig_timeout = sock_transp->timeout;
70 sock_transp->timeout = timeout;
72 return orig_timeout;
75 struct rpc_sock_read_state {
76 struct rpc_transport_sock_state *transp;
77 ssize_t received;
80 static void rpc_sock_read_done(struct tevent_req *subreq);
82 static struct async_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
83 struct event_context *ev,
84 uint8_t *data, size_t size,
85 void *priv)
87 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
88 priv, struct rpc_transport_sock_state);
89 struct async_req *result;
90 struct tevent_req *subreq;
91 struct rpc_sock_read_state *state;
92 struct timeval endtime;
94 if (!async_req_setup(mem_ctx, &result, &state,
95 struct rpc_sock_read_state)) {
96 return NULL;
98 if (!rpc_sock_is_connected(sock_transp)) {
99 if (!async_post_ntstatus(result, ev, NT_STATUS_CONNECTION_INVALID)) {
100 goto fail;
102 return result;
104 state->transp = sock_transp;
105 endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
106 subreq = async_recv_send(state, ev, sock_transp->fd, data, size, 0);
107 if (subreq == NULL) {
108 goto fail;
111 if (!tevent_req_set_endtime(subreq, ev, endtime)) {
112 goto fail;
115 tevent_req_set_callback(subreq, rpc_sock_read_done, result);
116 return result;
117 fail:
118 TALLOC_FREE(result);
119 return NULL;
122 static void rpc_sock_read_done(struct tevent_req *subreq)
124 struct async_req *req =
125 tevent_req_callback_data(subreq, struct async_req);
126 struct rpc_sock_read_state *state = talloc_get_type_abort(
127 req->private_data, struct rpc_sock_read_state);
128 int err;
130 /* We must free subreq in this function as there is
131 a timer event attached to it. */
133 state->received = async_recv_recv(subreq, &err);
135 if (state->received == -1) {
136 TALLOC_FREE(subreq);
137 rpc_sock_disconnect(state->transp);
138 async_req_nterror(req, map_nt_error_from_unix(err));
139 return;
141 TALLOC_FREE(subreq);
142 async_req_done(req);
145 static NTSTATUS rpc_sock_read_recv(struct async_req *req, ssize_t *preceived)
147 struct rpc_sock_read_state *state = talloc_get_type_abort(
148 req->private_data, struct rpc_sock_read_state);
149 NTSTATUS status;
151 if (async_req_is_nterror(req, &status)) {
152 return status;
154 *preceived = state->received;
155 return NT_STATUS_OK;
158 struct rpc_sock_write_state {
159 struct rpc_transport_sock_state *transp;
160 ssize_t sent;
163 static void rpc_sock_write_done(struct tevent_req *subreq);
165 static struct async_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
166 struct event_context *ev,
167 const uint8_t *data, size_t size,
168 void *priv)
170 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
171 priv, struct rpc_transport_sock_state);
172 struct async_req *result;
173 struct tevent_req *subreq;
174 struct rpc_sock_write_state *state;
175 struct timeval endtime;
177 if (!async_req_setup(mem_ctx, &result, &state,
178 struct rpc_sock_write_state)) {
179 return NULL;
181 if (!rpc_sock_is_connected(sock_transp)) {
182 if (!async_post_ntstatus(result, ev, NT_STATUS_CONNECTION_INVALID)) {
183 goto fail;
185 return result;
187 state->transp = sock_transp;
188 endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
189 subreq = async_send_send(state, ev, sock_transp->fd, data, size, 0);
190 if (subreq == NULL) {
191 goto fail;
194 if (!tevent_req_set_endtime(subreq, ev, endtime)) {
195 goto fail;
198 tevent_req_set_callback(subreq, rpc_sock_write_done, result);
199 return result;
200 fail:
201 TALLOC_FREE(result);
202 return NULL;
205 static void rpc_sock_write_done(struct tevent_req *subreq)
207 struct async_req *req =
208 tevent_req_callback_data(subreq, struct async_req);
209 struct rpc_sock_write_state *state = talloc_get_type_abort(
210 req->private_data, struct rpc_sock_write_state);
211 int err;
213 /* We must free subreq in this function as there is
214 a timer event attached to it. */
216 state->sent = async_send_recv(subreq, &err);
218 if (state->sent == -1) {
219 TALLOC_FREE(subreq);
220 rpc_sock_disconnect(state->transp);
221 async_req_nterror(req, map_nt_error_from_unix(err));
222 return;
224 TALLOC_FREE(subreq);
225 async_req_done(req);
228 static NTSTATUS rpc_sock_write_recv(struct async_req *req, ssize_t *psent)
230 struct rpc_sock_write_state *state = talloc_get_type_abort(
231 req->private_data, struct rpc_sock_write_state);
232 NTSTATUS status;
234 if (async_req_is_nterror(req, &status)) {
235 return status;
237 *psent = state->sent;
238 return NT_STATUS_OK;
241 NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
242 struct rpc_cli_transport **presult)
244 struct rpc_cli_transport *result;
245 struct rpc_transport_sock_state *state;
247 result = talloc(mem_ctx, struct rpc_cli_transport);
248 if (result == NULL) {
249 return NT_STATUS_NO_MEMORY;
251 state = talloc(result, struct rpc_transport_sock_state);
252 if (state == NULL) {
253 TALLOC_FREE(result);
254 return NT_STATUS_NO_MEMORY;
256 result->priv = state;
258 state->fd = fd;
259 state->timeout = 10000; /* 10 seconds. */
260 talloc_set_destructor(state, rpc_transport_sock_state_destructor);
262 result->trans_send = NULL;
263 result->trans_recv = NULL;
264 result->write_send = rpc_sock_write_send;
265 result->write_recv = rpc_sock_write_recv;
266 result->read_send = rpc_sock_read_send;
267 result->read_recv = rpc_sock_read_recv;
268 result->is_connected = rpc_sock_is_connected;
269 result->set_timeout = rpc_sock_set_timeout;
271 *presult = result;
272 return NT_STATUS_OK;