~lefteris-nikoltsios/+junk/samba-lp1016895

« back to all changes in this revision

Viewing changes to source3/libsmb/unexpected.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
*/
20
20
 
21
21
#include "includes.h"
22
 
 
23
 
static TDB_CONTEXT *tdbd = NULL;
24
 
 
25
 
/* the key type used in the unexpected packet database */
26
 
struct unexpected_key {
27
 
        enum packet_type packet_type;
 
22
#include "../lib/util/tevent_ntstatus.h"
 
23
#include "lib/async_req/async_sock.h"
 
24
#include "libsmb/nmblib.h"
 
25
 
 
26
static const char *nmbd_socket_dir(void)
 
27
{
 
28
        return lp_parm_const_string(-1, "nmbd", "socket dir",
 
29
                                    get_dyn_NMBDSOCKETDIR());
 
30
}
 
31
 
 
32
struct nb_packet_query {
 
33
        enum packet_type type;
 
34
        size_t mailslot_namelen;
 
35
        int trn_id;
 
36
};
 
37
 
 
38
struct nb_packet_client;
 
39
 
 
40
struct nb_packet_server {
 
41
        struct tevent_context *ev;
 
42
        int listen_sock;
 
43
        int max_clients;
 
44
        int num_clients;
 
45
        struct nb_packet_client *clients;
 
46
};
 
47
 
 
48
struct nb_packet_client {
 
49
        struct nb_packet_client *prev, *next;
 
50
        struct nb_packet_server *server;
 
51
 
 
52
        enum packet_type type;
 
53
        int trn_id;
 
54
        char *mailslot_name;
 
55
 
 
56
        int sock;
 
57
        struct tevent_req *read_req;
 
58
        struct tevent_queue *out_queue;
 
59
};
 
60
 
 
61
static int nb_packet_server_destructor(struct nb_packet_server *s);
 
62
static void nb_packet_server_listener(struct tevent_context *ev,
 
63
                                      struct tevent_fd *fde,
 
64
                                      uint16_t flags,
 
65
                                      void *private_data);
 
66
 
 
67
NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
 
68
                                 struct tevent_context *ev,
 
69
                                 int max_clients,
 
70
                                 struct nb_packet_server **presult)
 
71
{
 
72
        struct nb_packet_server *result;
 
73
        struct tevent_fd *fde;
 
74
        NTSTATUS status;
 
75
 
 
76
        result = TALLOC_ZERO_P(mem_ctx, struct nb_packet_server);
 
77
        if (result == NULL) {
 
78
                status = NT_STATUS_NO_MEMORY;
 
79
                goto fail;
 
80
        }
 
81
        result->ev = ev;
 
82
        result->max_clients = max_clients;
 
83
 
 
84
        result->listen_sock = create_pipe_sock(
 
85
                nmbd_socket_dir(), "unexpected", 0755);
 
86
        if (result->listen_sock == -1) {
 
87
                status = map_nt_error_from_unix(errno);
 
88
                goto fail;
 
89
        }
 
90
        talloc_set_destructor(result, nb_packet_server_destructor);
 
91
 
 
92
        fde = tevent_add_fd(ev, result, result->listen_sock, TEVENT_FD_READ,
 
93
                            nb_packet_server_listener, result);
 
94
        if (fde == NULL) {
 
95
                status = NT_STATUS_NO_MEMORY;
 
96
                goto fail;
 
97
        }
 
98
 
 
99
        *presult = result;
 
100
        return NT_STATUS_OK;
 
101
fail:
 
102
        TALLOC_FREE(result);
 
103
        return status;
 
104
}
 
105
 
 
106
static int nb_packet_server_destructor(struct nb_packet_server *s)
 
107
{
 
108
        if (s->listen_sock != -1) {
 
109
                close(s->listen_sock);
 
110
                s->listen_sock = -1;
 
111
        }
 
112
        return 0;
 
113
}
 
114
 
 
115
static int nb_packet_client_destructor(struct nb_packet_client *c);
 
116
static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
 
117
                                     void *private_data);
 
118
static void nb_packet_got_query(struct tevent_req *req);
 
119
static void nb_packet_client_read_done(struct tevent_req *req);
 
120
 
 
121
static void nb_packet_server_listener(struct tevent_context *ev,
 
122
                                      struct tevent_fd *fde,
 
123
                                      uint16_t flags,
 
124
                                      void *private_data)
 
125
{
 
126
        struct nb_packet_server *server = talloc_get_type_abort(
 
127
                private_data, struct nb_packet_server);
 
128
        struct nb_packet_client *client;
 
129
        struct tevent_req *req;
 
130
        struct sockaddr_un sunaddr;
 
131
        socklen_t len;
 
132
        int sock;
 
133
 
 
134
        len = sizeof(sunaddr);
 
135
 
 
136
        sock = accept(server->listen_sock, (struct sockaddr *)(void *)&sunaddr,
 
137
                      &len);
 
138
        if (sock == -1) {
 
139
                return;
 
140
        }
 
141
        DEBUG(6,("accepted socket %d\n", sock));
 
142
 
 
143
        client = TALLOC_ZERO_P(server, struct nb_packet_client);
 
144
        if (client == NULL) {
 
145
                DEBUG(10, ("talloc failed\n"));
 
146
                close(sock);
 
147
                return;
 
148
        }
 
149
        client->sock = sock;
 
150
        client->server = server;
 
151
        talloc_set_destructor(client, nb_packet_client_destructor);
 
152
 
 
153
        client->out_queue = tevent_queue_create(
 
154
                client, "unexpected packet output");
 
155
        if (client->out_queue == NULL) {
 
156
                DEBUG(10, ("tevent_queue_create failed\n"));
 
157
                TALLOC_FREE(client);
 
158
                return;
 
159
        }
 
160
 
 
161
        req = read_packet_send(client, ev, client->sock,
 
162
                               sizeof(struct nb_packet_query),
 
163
                               nb_packet_client_more, NULL);
 
164
        if (req == NULL) {
 
165
                DEBUG(10, ("read_packet_send failed\n"));
 
166
                TALLOC_FREE(client);
 
167
                return;
 
168
        }
 
169
        tevent_req_set_callback(req, nb_packet_got_query, client);
 
170
 
 
171
        DLIST_ADD(server->clients, client);
 
172
        server->num_clients += 1;
 
173
 
 
174
        if (server->num_clients > server->max_clients) {
 
175
                DEBUG(10, ("Too many clients, dropping oldest\n"));
 
176
 
 
177
                /*
 
178
                 * no TALLOC_FREE here, don't mess with the list structs
 
179
                 */
 
180
                talloc_free(server->clients->prev);
 
181
        }
 
182
}
 
183
 
 
184
static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
 
185
                                     void *private_data)
 
186
{
 
187
        struct nb_packet_query q;
 
188
        if (buflen > sizeof(struct nb_packet_query)) {
 
189
                return 0;
 
190
        }
 
191
        /* Take care of alignment */
 
192
        memcpy(&q, buf, sizeof(q));
 
193
        if (q.mailslot_namelen > 1024) {
 
194
                DEBUG(10, ("Got invalid mailslot namelen %d\n",
 
195
                           (int)q.mailslot_namelen));
 
196
                return -1;
 
197
        }
 
198
        return q.mailslot_namelen;
 
199
}
 
200
 
 
201
static int nb_packet_client_destructor(struct nb_packet_client *c)
 
202
{
 
203
        if (c->sock != -1) {
 
204
                close(c->sock);
 
205
                c->sock = -1;
 
206
        }
 
207
        DLIST_REMOVE(c->server->clients, c);
 
208
        c->server->num_clients -= 1;
 
209
        return 0;
 
210
}
 
211
 
 
212
static void nb_packet_got_query(struct tevent_req *req)
 
213
{
 
214
        struct nb_packet_client *client = tevent_req_callback_data(
 
215
                req, struct nb_packet_client);
 
216
        struct nb_packet_query q;
 
217
        uint8_t *buf;
 
218
        ssize_t nread, nwritten;
 
219
        int err;
 
220
        char c;
 
221
 
 
222
        nread = read_packet_recv(req, talloc_tos(), &buf, &err);
 
223
        TALLOC_FREE(req);
 
224
        if (nread < (ssize_t)sizeof(struct nb_packet_query)) {
 
225
                DEBUG(10, ("read_packet_recv returned %d (%s)\n",
 
226
                           (int)nread,
 
227
                           (nread == -1) ? strerror(err) : "wrong length"));
 
228
                TALLOC_FREE(client);
 
229
                return;
 
230
        }
 
231
 
 
232
        /* Take care of alignment */
 
233
        memcpy(&q, buf, sizeof(q));
 
234
 
 
235
        if (nread != sizeof(struct nb_packet_query) + q.mailslot_namelen) {
 
236
                DEBUG(10, ("nb_packet_got_query: Invalid mailslot namelength\n"));
 
237
                TALLOC_FREE(client);
 
238
                return;
 
239
        }
 
240
 
 
241
        client->trn_id = q.trn_id;
 
242
        client->type = q.type;
 
243
        if (q.mailslot_namelen > 0) {
 
244
                client->mailslot_name = talloc_strndup(
 
245
                        client, (char *)buf + sizeof(q),
 
246
                        q.mailslot_namelen);
 
247
                if (client->mailslot_name == NULL) {
 
248
                        TALLOC_FREE(client);
 
249
                        return;
 
250
                }
 
251
        }
 
252
 
 
253
        /*
 
254
         * Yes, this is a blocking write of 1 byte into a unix
 
255
         * domain socket that has never been written to. Highly
 
256
         * unlikely that this actually blocks.
 
257
         */
 
258
        c = 0;
 
259
        nwritten = sys_write(client->sock, &c, sizeof(c));
 
260
        if (nwritten != sizeof(c)) {
 
261
                DEBUG(10, ("Could not write success indicator to client: %s\n",
 
262
                           strerror(errno)));
 
263
                TALLOC_FREE(client);
 
264
                return;
 
265
        }
 
266
 
 
267
        client->read_req = read_packet_send(client, client->server->ev,
 
268
                                            client->sock, 1, NULL, NULL);
 
269
        if (client->read_req == NULL) {
 
270
                DEBUG(10, ("Could not activate reader for client exit "
 
271
                           "detection\n"));
 
272
                TALLOC_FREE(client);
 
273
                return;
 
274
        }
 
275
        tevent_req_set_callback(client->read_req, nb_packet_client_read_done,
 
276
                                client);
 
277
}
 
278
 
 
279
static void nb_packet_client_read_done(struct tevent_req *req)
 
280
{
 
281
        struct nb_packet_client *client = tevent_req_callback_data(
 
282
                req, struct nb_packet_client);
 
283
        ssize_t nread;
 
284
        uint8_t *buf;
 
285
        int err;
 
286
 
 
287
        nread = read_packet_recv(req, talloc_tos(), &buf, &err);
 
288
        TALLOC_FREE(req);
 
289
        if (nread == 1) {
 
290
                DEBUG(10, ("Protocol error, received data on write-only "
 
291
                           "unexpected socket: 0x%2.2x\n", (*buf)));
 
292
        }
 
293
        TALLOC_FREE(client);
 
294
}
 
295
 
 
296
static void nb_packet_client_send(struct nb_packet_client *client,
 
297
                                  struct packet_struct *p);
 
298
 
 
299
void nb_packet_dispatch(struct nb_packet_server *server,
 
300
                        struct packet_struct *p)
 
301
{
 
302
        struct nb_packet_client *c;
 
303
        uint16_t trn_id;
 
304
 
 
305
        switch (p->packet_type) {
 
306
        case NMB_PACKET:
 
307
                trn_id = p->packet.nmb.header.name_trn_id;
 
308
                break;
 
309
        case DGRAM_PACKET:
 
310
                trn_id = p->packet.dgram.header.dgm_id;
 
311
                break;
 
312
        default:
 
313
                DEBUG(10, ("Got invalid packet type %d\n",
 
314
                           (int)p->packet_type));
 
315
                return;
 
316
        }
 
317
        for (c = server->clients; c != NULL; c = c->next) {
 
318
 
 
319
                if (c->type != p->packet_type) {
 
320
                        DEBUG(10, ("client expects packet %d, got %d\n",
 
321
                                   c->type, p->packet_type));
 
322
                        continue;
 
323
                }
 
324
 
 
325
                if (p->packet_type == NMB_PACKET) {
 
326
                        /*
 
327
                         * See if the client specified transaction
 
328
                         * ID. Filter if it did.
 
329
                         */
 
330
                        if ((c->trn_id != -1) &&
 
331
                            (c->trn_id != trn_id)) {
 
332
                                DEBUG(10, ("client expects trn %d, got %d\n",
 
333
                                           c->trn_id, trn_id));
 
334
                                continue;
 
335
                        }
 
336
                } else {
 
337
                        /*
 
338
                         * See if the client specified a mailslot
 
339
                         * name. Filter if it did.
 
340
                         */
 
341
                        if ((c->mailslot_name != NULL) &&
 
342
                            !match_mailslot_name(p, c->mailslot_name)) {
 
343
                                continue;
 
344
                        }
 
345
                }
 
346
                nb_packet_client_send(c, p);
 
347
        }
 
348
}
 
349
 
 
350
struct nb_packet_client_header {
 
351
        size_t len;
 
352
        enum packet_type type;
28
353
        time_t timestamp;
29
 
        int count;
30
 
};
31
 
 
32
 
/****************************************************************************
33
 
 All unexpected packets are passed in here, to be stored in a unexpected
34
 
 packet database. This allows nmblookup and other tools to receive packets
35
 
 erroneously sent to the wrong port by broken MS systems.
36
 
**************************************************************************/
37
 
 
38
 
void unexpected_packet(struct packet_struct *p)
39
 
{
40
 
        static int count;
41
 
        TDB_DATA kbuf, dbuf;
42
 
        struct unexpected_key key;
43
 
        char buf[1024];
44
 
        int len=0;
45
 
        uint32_t enc_ip;
46
 
 
47
 
        if (!tdbd) {
48
 
                tdbd = tdb_open_log(lock_path("unexpected.tdb"), 0,
49
 
                               TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
50
 
                               O_RDWR | O_CREAT, 0644);
51
 
                if (!tdbd) {
52
 
                        DEBUG(0,("Failed to open unexpected.tdb\n"));
53
 
                        return;
54
 
                }
55
 
        }
56
 
 
57
 
        memset(buf,'\0',sizeof(buf));
58
 
 
59
 
        /* Encode the ip addr and port. */
60
 
        enc_ip = ntohl(p->ip.s_addr);
61
 
        SIVAL(buf,0,enc_ip);
62
 
        SSVAL(buf,4,p->port);
63
 
 
64
 
        len = build_packet(&buf[6], sizeof(buf)-6, p) + 6;
65
 
 
66
 
        ZERO_STRUCT(key);       /* needed for potential alignment */
67
 
 
68
 
        key.packet_type = p->packet_type;
69
 
        key.timestamp = p->timestamp;
70
 
        key.count = count++;
71
 
 
72
 
        kbuf.dptr = (uint8_t *)&key;
73
 
        kbuf.dsize = sizeof(key);
74
 
        dbuf.dptr = (uint8_t *)buf;
75
 
        dbuf.dsize = len;
76
 
 
77
 
        tdb_store(tdbd, kbuf, dbuf, TDB_REPLACE);
78
 
}
79
 
 
80
 
 
81
 
static time_t lastt;
82
 
 
83
 
/****************************************************************************
84
 
 Delete the record if it is too old.
85
 
**************************************************************************/
86
 
 
87
 
static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
88
 
{
89
 
        struct unexpected_key key;
90
 
 
91
 
        if (kbuf.dsize != sizeof(key)) {
92
 
                tdb_delete(ttdb, kbuf);
93
 
        }
94
 
 
95
 
        memcpy(&key, kbuf.dptr, sizeof(key));
96
 
 
97
 
        if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
98
 
                tdb_delete(ttdb, kbuf);
99
 
        }
100
 
 
101
 
        return 0;
102
 
}
103
 
 
104
 
 
105
 
/****************************************************************************
106
 
 Delete all old unexpected packets.
107
 
**************************************************************************/
108
 
 
109
 
void clear_unexpected(time_t t)
110
 
{
111
 
        if (!tdbd) return;
112
 
 
113
 
        if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
114
 
                return;
115
 
 
116
 
        lastt = t;
117
 
 
118
 
        tdb_traverse(tdbd, traverse_fn, NULL);
119
 
}
120
 
 
121
 
struct receive_unexpected_state {
122
 
        struct packet_struct *matched_packet;
123
 
        int match_id;
124
 
        enum packet_type match_type;
125
 
        const char *match_name;
126
 
};
127
 
 
128
 
/****************************************************************************
129
 
 tdb traversal fn to find a matching 137 packet.
130
 
**************************************************************************/
131
 
 
132
 
static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
133
 
                          void *private_data)
134
 
{
135
 
        struct receive_unexpected_state *state =
136
 
                (struct receive_unexpected_state *)private_data;
137
 
        struct unexpected_key key;
138
354
        struct in_addr ip;
139
 
        uint32_t enc_ip;
140
355
        int port;
141
 
        struct packet_struct *p;
142
 
 
143
 
        if (kbuf.dsize != sizeof(key)) {
144
 
                return 0;
145
 
        }
146
 
 
147
 
        memcpy(&key, kbuf.dptr, sizeof(key));
148
 
 
149
 
        if (key.packet_type != state->match_type) return 0;
150
 
 
151
 
        if (dbuf.dsize < 6) {
152
 
                return 0;
153
 
        }
154
 
 
155
 
        /* Decode the ip addr and port. */
156
 
        enc_ip = IVAL(dbuf.dptr,0);
157
 
        ip.s_addr = htonl(enc_ip);
158
 
        port = SVAL(dbuf.dptr,4);
159
 
 
160
 
        p = parse_packet((char *)&dbuf.dptr[6],
161
 
                        dbuf.dsize-6,
162
 
                        state->match_type,
163
 
                        ip,
164
 
                        port);
165
 
        if (!p)
166
 
                return 0;
167
 
 
168
 
        if ((state->match_type == NMB_PACKET &&
169
 
             p->packet.nmb.header.name_trn_id == state->match_id) ||
170
 
            (state->match_type == DGRAM_PACKET &&
171
 
             match_mailslot_name(p, state->match_name))) {
172
 
                state->matched_packet = p;
173
 
                return -1;
174
 
        }
175
 
 
176
 
        free_packet(p);
177
 
 
178
 
        return 0;
179
 
}
180
 
 
181
 
/****************************************************************************
182
 
 Check for a particular packet in the unexpected packet queue.
183
 
**************************************************************************/
184
 
 
185
 
struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
 
356
};
 
357
 
 
358
struct nb_packet_client_state {
 
359
        struct nb_packet_client *client;
 
360
        struct iovec iov[2];
 
361
        struct nb_packet_client_header hdr;
 
362
        char buf[1024];
 
363
};
 
364
 
 
365
static void nb_packet_client_send_done(struct tevent_req *req);
 
366
 
 
367
static void nb_packet_client_send(struct nb_packet_client *client,
 
368
                                  struct packet_struct *p)
 
369
{
 
370
        struct nb_packet_client_state *state;
 
371
        struct tevent_req *req;
 
372
 
 
373
        if (tevent_queue_length(client->out_queue) > 10) {
 
374
                /*
 
375
                 * Skip clients that don't listen anyway, some form of DoS
 
376
                 * protection
 
377
                 */
 
378
                return;
 
379
        }
 
380
 
 
381
        state = TALLOC_ZERO_P(client, struct nb_packet_client_state);
 
382
        if (state == NULL) {
 
383
                DEBUG(10, ("talloc failed\n"));
 
384
                return;
 
385
        }
 
386
 
 
387
        state->client = client;
 
388
 
 
389
        state->hdr.ip = p->ip;
 
390
        state->hdr.port = p->port;
 
391
        state->hdr.timestamp = p->timestamp;
 
392
        state->hdr.type = p->packet_type;
 
393
        state->hdr.len = build_packet(state->buf, sizeof(state->buf), p);
 
394
 
 
395
        state->iov[0].iov_base = (char *)&state->hdr;
 
396
        state->iov[0].iov_len = sizeof(state->hdr);
 
397
        state->iov[1].iov_base = state->buf;
 
398
        state->iov[1].iov_len = state->hdr.len;
 
399
 
 
400
        TALLOC_FREE(client->read_req);
 
401
 
 
402
        req = writev_send(client, client->server->ev, client->out_queue,
 
403
                          client->sock, true, state->iov, 2);
 
404
        if (req == NULL) {
 
405
                DEBUG(10, ("writev_send failed\n"));
 
406
                return;
 
407
        }
 
408
        tevent_req_set_callback(req, nb_packet_client_send_done, state);
 
409
}
 
410
 
 
411
static void nb_packet_client_send_done(struct tevent_req *req)
 
412
{
 
413
        struct nb_packet_client_state *state = tevent_req_callback_data(
 
414
                req, struct nb_packet_client_state);
 
415
        struct nb_packet_client *client = state->client;
 
416
        ssize_t nwritten;
 
417
        int err;
 
418
 
 
419
        nwritten = writev_recv(req, &err);
 
420
 
 
421
        TALLOC_FREE(req);
 
422
        TALLOC_FREE(state);
 
423
 
 
424
        if (nwritten == -1) {
 
425
                DEBUG(10, ("writev failed: %s\n", strerror(err)));
 
426
                TALLOC_FREE(client);
 
427
        }
 
428
 
 
429
        if (tevent_queue_length(client->out_queue) == 0) {
 
430
                client->read_req = read_packet_send(client, client->server->ev,
 
431
                                                    client->sock, 1,
 
432
                                                    NULL, NULL);
 
433
                if (client->read_req == NULL) {
 
434
                        DEBUG(10, ("Could not activate reader for client exit "
 
435
                                   "detection\n"));
 
436
                        TALLOC_FREE(client);
 
437
                        return;
 
438
                }
 
439
                tevent_req_set_callback(client->read_req,
 
440
                                        nb_packet_client_read_done,
 
441
                                        client);
 
442
        }
 
443
}
 
444
 
 
445
struct nb_packet_reader {
 
446
        int sock;
 
447
};
 
448
 
 
449
struct nb_packet_reader_state {
 
450
        struct tevent_context *ev;
 
451
        struct sockaddr_un addr;
 
452
        struct nb_packet_query query;
 
453
        const char *mailslot_name;
 
454
        struct iovec iov[2];
 
455
        char c;
 
456
        struct nb_packet_reader *reader;
 
457
};
 
458
 
 
459
static int nb_packet_reader_destructor(struct nb_packet_reader *r);
 
460
static void nb_packet_reader_connected(struct tevent_req *subreq);
 
461
static void nb_packet_reader_sent_query(struct tevent_req *subreq);
 
462
static void nb_packet_reader_got_ack(struct tevent_req *subreq);
 
463
 
 
464
struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
 
465
                                         struct tevent_context *ev,
 
466
                                         enum packet_type type,
 
467
                                         int trn_id,
186
468
                                         const char *mailslot_name)
187
469
{
188
 
        TDB_CONTEXT *tdb2;
189
 
        struct receive_unexpected_state state;
190
 
 
191
 
        tdb2 = tdb_open_log(lock_path("unexpected.tdb"), 0, 0, O_RDONLY, 0);
192
 
        if (!tdb2) return NULL;
193
 
 
194
 
        state.matched_packet = NULL;
195
 
        state.match_id = id;
196
 
        state.match_type = packet_type;
197
 
        state.match_name = mailslot_name;
198
 
 
199
 
        tdb_traverse(tdb2, traverse_match, &state);
200
 
 
201
 
        tdb_close(tdb2);
202
 
 
203
 
        return state.matched_packet;
 
470
        struct tevent_req *req, *subreq;
 
471
        struct nb_packet_reader_state *state;
 
472
        char *path;
 
473
 
 
474
        req = tevent_req_create(mem_ctx, &state,
 
475
                                struct nb_packet_reader_state);
 
476
        if (req == NULL) {
 
477
                return NULL;
 
478
        }
 
479
        state->ev = ev;
 
480
        state->query.trn_id = trn_id;
 
481
        state->query.type = type;
 
482
        state->mailslot_name = mailslot_name;
 
483
 
 
484
        if (mailslot_name != NULL) {
 
485
                state->query.mailslot_namelen = strlen(mailslot_name);
 
486
        }
 
487
 
 
488
        state->reader = TALLOC_ZERO_P(state, struct nb_packet_reader);
 
489
        if (tevent_req_nomem(state->reader, req)) {
 
490
                return tevent_req_post(req, ev);
 
491
        }
 
492
 
 
493
        path = talloc_asprintf(talloc_tos(), "%s/%s", nmbd_socket_dir(),
 
494
                               "unexpected");
 
495
        if (tevent_req_nomem(path, req)) {
 
496
                return tevent_req_post(req, ev);
 
497
        }
 
498
        state->addr.sun_family = AF_UNIX;
 
499
        strlcpy(state->addr.sun_path, path, sizeof(state->addr.sun_path));
 
500
        TALLOC_FREE(path);
 
501
 
 
502
        state->reader->sock = socket(AF_UNIX, SOCK_STREAM, 0);
 
503
        if (state->reader->sock == -1) {
 
504
                tevent_req_nterror(req, map_nt_error_from_unix(errno));
 
505
                return tevent_req_post(req, ev);
 
506
        }
 
507
        talloc_set_destructor(state->reader, nb_packet_reader_destructor);
 
508
 
 
509
        subreq = async_connect_send(state, ev, state->reader->sock,
 
510
                                    (struct sockaddr *)(void *)&state->addr,
 
511
                                    sizeof(state->addr));
 
512
        if (tevent_req_nomem(subreq, req)) {
 
513
                return tevent_req_post(req, ev);
 
514
        }
 
515
        tevent_req_set_callback(subreq, nb_packet_reader_connected, req);
 
516
        return req;
 
517
}
 
518
 
 
519
static int nb_packet_reader_destructor(struct nb_packet_reader *r)
 
520
{
 
521
        if (r->sock != -1) {
 
522
                close(r->sock);
 
523
                r->sock = -1;
 
524
        }
 
525
        return 0;
 
526
}
 
527
 
 
528
static void nb_packet_reader_connected(struct tevent_req *subreq)
 
529
{
 
530
        struct tevent_req *req = tevent_req_callback_data(
 
531
                subreq, struct tevent_req);
 
532
        struct nb_packet_reader_state *state = tevent_req_data(
 
533
                req, struct nb_packet_reader_state);
 
534
        int res, err;
 
535
        int num_iovecs = 1;
 
536
 
 
537
        res = async_connect_recv(subreq, &err);
 
538
        TALLOC_FREE(subreq);
 
539
        if (res == -1) {
 
540
                DEBUG(10, ("async_connect failed: %s\n", strerror(err)));
 
541
                tevent_req_nterror(req, map_nt_error_from_unix(err));
 
542
                return;
 
543
        }
 
544
 
 
545
        state->iov[0].iov_base = (char *)&state->query;
 
546
        state->iov[0].iov_len = sizeof(state->query);
 
547
 
 
548
        if (state->mailslot_name != NULL) {
 
549
                num_iovecs = 2;
 
550
                state->iov[1].iov_base = discard_const_p(
 
551
                        char, state->mailslot_name);
 
552
                state->iov[1].iov_len = state->query.mailslot_namelen;
 
553
        }
 
554
 
 
555
        subreq = writev_send(state, state->ev, NULL, state->reader->sock,
 
556
                             true, state->iov, num_iovecs);
 
557
        if (tevent_req_nomem(subreq, req)) {
 
558
                return;
 
559
        }
 
560
        tevent_req_set_callback(subreq, nb_packet_reader_sent_query, req);
 
561
}
 
562
 
 
563
static void nb_packet_reader_sent_query(struct tevent_req *subreq)
 
564
{
 
565
        struct tevent_req *req = tevent_req_callback_data(
 
566
                subreq, struct tevent_req);
 
567
        struct nb_packet_reader_state *state = tevent_req_data(
 
568
                req, struct nb_packet_reader_state);
 
569
        ssize_t written;
 
570
        int err;
 
571
 
 
572
        written = writev_recv(subreq, &err);
 
573
        TALLOC_FREE(subreq);
 
574
        if (written == -1) {
 
575
                tevent_req_nterror(req, map_nt_error_from_unix(err));
 
576
                return;
 
577
        }
 
578
        if (written != sizeof(state->query) + state->query.mailslot_namelen) {
 
579
                tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
 
580
                return;
 
581
        }
 
582
        subreq = read_packet_send(state, state->ev, state->reader->sock,
 
583
                                  sizeof(state->c), NULL, NULL);
 
584
        if (tevent_req_nomem(subreq, req)) {
 
585
                return;
 
586
        }
 
587
        tevent_req_set_callback(subreq, nb_packet_reader_got_ack, req);
 
588
}
 
589
 
 
590
static void nb_packet_reader_got_ack(struct tevent_req *subreq)
 
591
{
 
592
        struct tevent_req *req = tevent_req_callback_data(
 
593
                subreq, struct tevent_req);
 
594
        struct nb_packet_reader_state *state = tevent_req_data(
 
595
                req, struct nb_packet_reader_state);
 
596
        ssize_t nread;
 
597
        int err;
 
598
        uint8_t *buf;
 
599
 
 
600
        nread = read_packet_recv(subreq, state, &buf, &err);
 
601
        TALLOC_FREE(subreq);
 
602
        if (nread == -1) {
 
603
                DEBUG(10, ("read_packet_recv returned %s\n",
 
604
                           strerror(err)));
 
605
                tevent_req_nterror(req, map_nt_error_from_unix(err));
 
606
                return;
 
607
        }
 
608
        if (nread != sizeof(state->c)) {
 
609
                DEBUG(10, ("read = %d, expected %d\n", (int)nread,
 
610
                           (int)sizeof(state->c)));
 
611
                tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
 
612
                return;
 
613
        }
 
614
        tevent_req_done(req);
 
615
}
 
616
 
 
617
NTSTATUS nb_packet_reader_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 
618
                               struct nb_packet_reader **preader)
 
619
{
 
620
        struct nb_packet_reader_state *state = tevent_req_data(
 
621
                req, struct nb_packet_reader_state);
 
622
        NTSTATUS status;
 
623
 
 
624
        if (tevent_req_is_nterror(req, &status)) {
 
625
                return status;
 
626
        }
 
627
        *preader = talloc_move(mem_ctx, &state->reader);
 
628
        return NT_STATUS_OK;
 
629
}
 
630
 
 
631
struct nb_packet_read_state {
 
632
        struct nb_packet_client_header hdr;
 
633
        uint8_t *buf;
 
634
        size_t buflen;
 
635
};
 
636
 
 
637
static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p);
 
638
static void nb_packet_read_done(struct tevent_req *subreq);
 
639
 
 
640
struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
 
641
                                       struct tevent_context *ev,
 
642
                                       struct nb_packet_reader *reader)
 
643
{
 
644
        struct tevent_req *req, *subreq;
 
645
        struct nb_packet_read_state *state;
 
646
 
 
647
        req = tevent_req_create(mem_ctx, &state, struct nb_packet_read_state);
 
648
        if (req == NULL) {
 
649
                return NULL;
 
650
        }
 
651
        subreq = read_packet_send(state, ev, reader->sock,
 
652
                                  sizeof(struct nb_packet_client_header),
 
653
                                  nb_packet_read_more, state);
 
654
        if (tevent_req_nomem(subreq, req)) {
 
655
                return tevent_req_post(req, ev);
 
656
        }
 
657
        tevent_req_set_callback(subreq, nb_packet_read_done, req);
 
658
        return req;
 
659
}
 
660
 
 
661
static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p)
 
662
{
 
663
        struct nb_packet_read_state *state = talloc_get_type_abort(
 
664
                p, struct nb_packet_read_state);
 
665
 
 
666
        if (buflen > sizeof(struct nb_packet_client_header)) {
 
667
                /*
 
668
                 * Been here, done
 
669
                 */
 
670
                return 0;
 
671
        }
 
672
        memcpy(&state->hdr, buf, sizeof(struct nb_packet_client_header));
 
673
        return state->hdr.len;
 
674
}
 
675
 
 
676
static void nb_packet_read_done(struct tevent_req *subreq)
 
677
{
 
678
        struct tevent_req *req = tevent_req_callback_data(
 
679
                subreq, struct tevent_req);
 
680
        struct nb_packet_read_state *state = tevent_req_data(
 
681
                req, struct nb_packet_read_state);
 
682
        ssize_t nread;
 
683
        int err;
 
684
 
 
685
        nread = read_packet_recv(subreq, state, &state->buf, &err);
 
686
        if (nread == -1) {
 
687
                tevent_req_nterror(req, map_nt_error_from_unix(err));
 
688
                return;
 
689
        }
 
690
        state->buflen = nread;
 
691
        tevent_req_done(req);
 
692
}
 
693
 
 
694
NTSTATUS nb_packet_read_recv(struct tevent_req *req,
 
695
                             struct packet_struct **ppacket)
 
696
{
 
697
        struct nb_packet_read_state *state = tevent_req_data(
 
698
                req, struct nb_packet_read_state);
 
699
        struct nb_packet_client_header hdr;
 
700
        struct packet_struct *packet;
 
701
        NTSTATUS status;
 
702
 
 
703
        if (tevent_req_is_nterror(req, &status)) {
 
704
                return status;
 
705
        }
 
706
 
 
707
        memcpy(&hdr, state->buf, sizeof(hdr));
 
708
 
 
709
        packet = parse_packet(
 
710
                (char *)state->buf + sizeof(struct nb_packet_client_header),
 
711
                state->buflen - sizeof(struct nb_packet_client_header),
 
712
                state->hdr.type, state->hdr.ip, state->hdr.port);
 
713
        if (packet == NULL) {
 
714
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
 
715
        }
 
716
        *ppacket = packet;
 
717
        return NT_STATUS_OK;
204
718
}