Fix bug #8972 - Directory group write permission bit is set if unix extensions are...
[samba.git] / source3 / rpc_client / rpc_transport_sock.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC client transport over a socket
4  *  Copyright (C) Volker Lendecke 2009
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "includes.h"
21
22 #undef DBGC_CLASS
23 #define DBGC_CLASS DBGC_RPC_CLI
24
25 struct rpc_transport_sock_state {
26         int fd;
27         int timeout;
28 };
29
30 static void rpc_sock_disconnect(struct rpc_transport_sock_state *s)
31 {
32         if (s->fd != -1) {
33                 close(s->fd);
34                 s->fd = -1;
35         }
36 }
37
38 static int rpc_transport_sock_state_destructor(struct rpc_transport_sock_state *s)
39 {
40         rpc_sock_disconnect(s);
41         return 0;
42 }
43
44 static bool rpc_sock_is_connected(void *priv)
45 {
46         struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
47                 priv, struct rpc_transport_sock_state);
48
49         if (sock_transp->fd == -1) {
50                 return false;
51         }
52
53         return true;
54 }
55
56 static unsigned int rpc_sock_set_timeout(void *priv, unsigned int timeout)
57 {
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;
62
63         ok = rpc_sock_is_connected(sock_transp);
64         if (!ok) {
65                 return 0;
66         }
67
68         orig_timeout = sock_transp->timeout;
69
70         sock_transp->timeout = timeout;
71
72         return orig_timeout;
73 }
74
75 struct rpc_sock_read_state {
76         struct rpc_transport_sock_state *transp;
77         ssize_t received;
78 };
79
80 static void rpc_sock_read_done(struct tevent_req *subreq);
81
82 static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
83                                              struct event_context *ev,
84                                              uint8_t *data, size_t size,
85                                              void *priv)
86 {
87         struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
88                 priv, struct rpc_transport_sock_state);
89         struct tevent_req *req, *subreq;
90         struct rpc_sock_read_state *state;
91         struct timeval endtime;
92
93         req = tevent_req_create(mem_ctx, &state, struct rpc_sock_read_state);
94         if (req == NULL) {
95                 return NULL;
96         }
97         if (!rpc_sock_is_connected(sock_transp)) {
98                 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
99                 return tevent_req_post(req, ev);
100         }
101         state->transp = sock_transp;
102         endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
103         subreq = async_recv_send(state, ev, sock_transp->fd, data, size, 0);
104         if (subreq == NULL) {
105                 goto fail;
106         }
107
108         if (!tevent_req_set_endtime(subreq, ev, endtime)) {
109                 goto fail;
110         }
111
112         tevent_req_set_callback(subreq, rpc_sock_read_done, req);
113         return req;
114  fail:
115         TALLOC_FREE(req);
116         return NULL;
117 }
118
119 static void rpc_sock_read_done(struct tevent_req *subreq)
120 {
121         struct tevent_req *req = tevent_req_callback_data(
122                 subreq, struct tevent_req);
123         struct rpc_sock_read_state *state = tevent_req_data(
124                 req, struct rpc_sock_read_state);
125         int err;
126
127         /* We must free subreq in this function as there is
128           a timer event attached to it. */
129
130         state->received = async_recv_recv(subreq, &err);
131
132         if (state->received == -1) {
133                 TALLOC_FREE(subreq);
134                 rpc_sock_disconnect(state->transp);
135                 tevent_req_nterror(req, map_nt_error_from_unix(err));
136                 return;
137         }
138         TALLOC_FREE(subreq);
139         tevent_req_done(req);
140 }
141
142 static NTSTATUS rpc_sock_read_recv(struct tevent_req *req, ssize_t *preceived)
143 {
144         struct rpc_sock_read_state *state = tevent_req_data(
145                 req, struct rpc_sock_read_state);
146         NTSTATUS status;
147
148         if (tevent_req_is_nterror(req, &status)) {
149                 return status;
150         }
151         *preceived = state->received;
152         return NT_STATUS_OK;
153 }
154
155 struct rpc_sock_write_state {
156         struct rpc_transport_sock_state *transp;
157         ssize_t sent;
158 };
159
160 static void rpc_sock_write_done(struct tevent_req *subreq);
161
162 static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
163                                               struct event_context *ev,
164                                               const uint8_t *data, size_t size,
165                                               void *priv)
166 {
167         struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
168                 priv, struct rpc_transport_sock_state);
169         struct tevent_req *req, *subreq;
170         struct rpc_sock_write_state *state;
171         struct timeval endtime;
172
173         req = tevent_req_create(mem_ctx, &state, struct rpc_sock_write_state);
174         if (req == NULL) {
175                 return NULL;
176         }
177         if (!rpc_sock_is_connected(sock_transp)) {
178                 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
179                 return tevent_req_post(req, ev);
180         }
181         state->transp = sock_transp;
182         endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
183         subreq = async_send_send(state, ev, sock_transp->fd, data, size, 0);
184         if (subreq == NULL) {
185                 goto fail;
186         }
187
188         if (!tevent_req_set_endtime(subreq, ev, endtime)) {
189                 goto fail;
190         }
191
192         tevent_req_set_callback(subreq, rpc_sock_write_done, req);
193         return req;
194  fail:
195         TALLOC_FREE(req);
196         return NULL;
197 }
198
199 static void rpc_sock_write_done(struct tevent_req *subreq)
200 {
201         struct tevent_req *req = tevent_req_callback_data(
202                 subreq, struct tevent_req);
203         struct rpc_sock_write_state *state = tevent_req_data(
204                 req, struct rpc_sock_write_state);
205         int err;
206
207         /* We must free subreq in this function as there is
208           a timer event attached to it. */
209
210         state->sent = async_send_recv(subreq, &err);
211
212         if (state->sent == -1) {
213                 TALLOC_FREE(subreq);
214                 rpc_sock_disconnect(state->transp);
215                 tevent_req_nterror(req, map_nt_error_from_unix(err));
216                 return;
217         }
218         TALLOC_FREE(subreq);
219         tevent_req_done(req);
220 }
221
222 static NTSTATUS rpc_sock_write_recv(struct tevent_req *req, ssize_t *psent)
223 {
224         struct rpc_sock_write_state *state = tevent_req_data(
225                 req, struct rpc_sock_write_state);
226         NTSTATUS status;
227
228         if (tevent_req_is_nterror(req, &status)) {
229                 return status;
230         }
231         *psent = state->sent;
232         return NT_STATUS_OK;
233 }
234
235 NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
236                                  struct rpc_cli_transport **presult)
237 {
238         struct rpc_cli_transport *result;
239         struct rpc_transport_sock_state *state;
240
241         result = talloc(mem_ctx, struct rpc_cli_transport);
242         if (result == NULL) {
243                 return NT_STATUS_NO_MEMORY;
244         }
245         state = talloc(result, struct rpc_transport_sock_state);
246         if (state == NULL) {
247                 TALLOC_FREE(result);
248                 return NT_STATUS_NO_MEMORY;
249         }
250         result->priv = state;
251
252         state->fd = fd;
253         state->timeout = 10000; /* 10 seconds. */
254         talloc_set_destructor(state, rpc_transport_sock_state_destructor);
255
256         result->trans_send = NULL;
257         result->trans_recv = NULL;
258         result->write_send = rpc_sock_write_send;
259         result->write_recv = rpc_sock_write_recv;
260         result->read_send = rpc_sock_read_send;
261         result->read_recv = rpc_sock_read_recv;
262         result->is_connected = rpc_sock_is_connected;
263         result->set_timeout = rpc_sock_set_timeout;
264
265         *presult = result;
266         return NT_STATUS_OK;
267 }