Fix bug #9100 - winbind doesn't return "Domain Local" groups from own domain.
[samba.git] / source3 / lib / packet.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Packet handling
4    Copyright (C) Volker Lendecke 2007
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 struct packet_context {
23         int fd;
24         DATA_BLOB in, out;
25 };
26
27 /*
28  * Close the underlying fd
29  */
30 static int packet_context_destructor(struct packet_context *ctx)
31 {
32         return close(ctx->fd);
33 }
34
35 /*
36  * Initialize a packet context. The fd is given to the packet context, meaning
37  * that it is automatically closed when the packet context is freed.
38  */
39 struct packet_context *packet_init(TALLOC_CTX *mem_ctx, int fd)
40 {
41         struct packet_context *result;
42
43         if (!(result = TALLOC_ZERO_P(mem_ctx, struct packet_context))) {
44                 return NULL;
45         }
46
47         result->fd = fd;
48         talloc_set_destructor(result, packet_context_destructor);
49         return result;
50 }
51
52 /*
53  * Pull data from the fd
54  */
55 NTSTATUS packet_fd_read(struct packet_context *ctx)
56 {
57         int res, available;
58         size_t new_size;
59         uint8 *in;
60
61         res = ioctl(ctx->fd, FIONREAD, &available);
62
63         if (res == -1) {
64                 DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", strerror(errno)));
65                 return map_nt_error_from_unix(errno);
66         }
67
68         SMB_ASSERT(available >= 0);
69
70         if (available == 0) {
71                 return NT_STATUS_END_OF_FILE;
72         }
73
74         new_size = ctx->in.length + available;
75
76         if (new_size < ctx->in.length) {
77                 DEBUG(0, ("integer wrap\n"));
78                 return NT_STATUS_NO_MEMORY;
79         }
80
81         if (!(in = TALLOC_REALLOC_ARRAY(ctx, ctx->in.data, uint8, new_size))) {
82                 DEBUG(10, ("talloc failed\n"));
83                 return NT_STATUS_NO_MEMORY;
84         }
85
86         ctx->in.data = in;
87
88         res = recv(ctx->fd, in + ctx->in.length, available, 0);
89
90         if (res < 0) {
91                 DEBUG(10, ("recv failed: %s\n", strerror(errno)));
92                 return map_nt_error_from_unix(errno);
93         }
94
95         if (res == 0) {
96                 return NT_STATUS_END_OF_FILE;
97         }
98
99         ctx->in.length += res;
100
101         return NT_STATUS_OK;
102 }
103
104 NTSTATUS packet_fd_read_sync(struct packet_context *ctx,
105                              struct timeval *timeout)
106 {
107         int res;
108         fd_set r_fds;
109
110         if (ctx->fd < 0 || ctx->fd >= FD_SETSIZE) {
111                 errno = EBADF;
112                 return map_nt_error_from_unix(errno);
113         }
114
115         FD_ZERO(&r_fds);
116         FD_SET(ctx->fd, &r_fds);
117
118         res = sys_select(ctx->fd+1, &r_fds, NULL, NULL, timeout);
119
120         if (res == 0) {
121                 DEBUG(10, ("select timed out\n"));
122                 return NT_STATUS_IO_TIMEOUT;
123         }
124
125         if (res == -1) {
126                 DEBUG(10, ("select returned %s\n", strerror(errno)));
127                 return map_nt_error_from_unix(errno);
128         }
129
130         return packet_fd_read(ctx);
131 }
132
133 bool packet_handler(struct packet_context *ctx,
134                     bool (*full_req)(const uint8_t *buf,
135                                      size_t available,
136                                      size_t *length,
137                                      void *priv),
138                     NTSTATUS (*callback)(uint8_t *buf, size_t length,
139                                          void *priv),
140                     void *priv, NTSTATUS *status)
141 {
142         size_t length;
143         uint8_t *buf;
144
145         if (!full_req(ctx->in.data, ctx->in.length, &length, priv)) {
146                 return False;
147         }
148
149         if (length > ctx->in.length) {
150                 *status = NT_STATUS_INTERNAL_ERROR;
151                 return true;
152         }
153
154         if (length == ctx->in.length) {
155                 buf = ctx->in.data;
156                 ctx->in.data = NULL;
157                 ctx->in.length = 0;
158         } else {
159                 buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length);
160                 if (buf == NULL) {
161                         *status = NT_STATUS_NO_MEMORY;
162                         return true;
163                 }
164
165                 memmove(ctx->in.data, ctx->in.data + length,
166                         ctx->in.length - length);
167                 ctx->in.length -= length;
168         }
169
170         *status = callback(buf, length, priv);
171         return True;
172 }
173
174 /*
175  * How many bytes of outgoing data do we have pending?
176  */
177 size_t packet_outgoing_bytes(struct packet_context *ctx)
178 {
179         return ctx->out.length;
180 }
181
182 /*
183  * Push data to the fd
184  */
185 NTSTATUS packet_fd_write(struct packet_context *ctx)
186 {
187         ssize_t sent;
188
189         sent = send(ctx->fd, ctx->out.data, ctx->out.length, 0);
190
191         if (sent == -1) {
192                 DEBUG(0, ("send failed: %s\n", strerror(errno)));
193                 return map_nt_error_from_unix(errno);
194         }
195
196         memmove(ctx->out.data, ctx->out.data + sent,
197                 ctx->out.length - sent);
198         ctx->out.length -= sent;
199
200         return NT_STATUS_OK;
201 }
202
203 /*
204  * Sync flush all outgoing bytes
205  */
206 NTSTATUS packet_flush(struct packet_context *ctx)
207 {
208         while (ctx->out.length != 0) {
209                 NTSTATUS status = packet_fd_write(ctx);
210                 if (!NT_STATUS_IS_OK(status)) {
211                         return status;
212                 }
213         }
214         return NT_STATUS_OK;
215 }
216
217 /*
218  * Send a list of DATA_BLOBs
219  *
220  * Example:  packet_send(ctx, 2, data_blob_const(&size, sizeof(size)),
221  *                       data_blob_const(buf, size));
222  */
223 NTSTATUS packet_send(struct packet_context *ctx, int num_blobs, ...)
224 {
225         va_list ap;
226         int i;
227         size_t len;
228         uint8 *out;
229
230         len = ctx->out.length;
231
232         va_start(ap, num_blobs);
233         for (i=0; i<num_blobs; i++) {
234                 size_t tmp;
235                 DATA_BLOB blob = va_arg(ap, DATA_BLOB);
236
237                 tmp = len + blob.length;
238                 if (tmp < len) {
239                         DEBUG(0, ("integer overflow\n"));
240                         va_end(ap);
241                         return NT_STATUS_NO_MEMORY;
242                 }
243                 len = tmp;
244         }
245         va_end(ap);
246
247         if (len == 0) {
248                 return NT_STATUS_OK;
249         }
250
251         if (!(out = TALLOC_REALLOC_ARRAY(ctx, ctx->out.data, uint8, len))) {
252                 DEBUG(0, ("talloc failed\n"));
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         ctx->out.data = out;
257
258         va_start(ap, num_blobs);
259         for (i=0; i<num_blobs; i++) {
260                 DATA_BLOB blob = va_arg(ap, DATA_BLOB);
261
262                 memcpy(ctx->out.data+ctx->out.length, blob.data, blob.length);
263                 ctx->out.length += blob.length;
264         }
265         va_end(ap);
266
267         SMB_ASSERT(ctx->out.length == len);
268         return NT_STATUS_OK;
269 }
270
271 /*
272  * Get the packet context's file descriptor
273  */
274 int packet_get_fd(struct packet_context *ctx)
275 {
276         return ctx->fd;
277 }
278