smbd: Reduce the complexity of open_file_ntcreate
[mat/samba.git] / source3 / libsmb / unexpected.c
index ce1e31dc59feefd6da6e84a3072b78c46accb5f2..2c01bb7515407784f174b9637167a8633c561d74 100644 (file)
 */
 
 #include "includes.h"
+#include "../lib/util/tevent_ntstatus.h"
 #include "lib/async_req/async_sock.h"
-
-static struct tdb_wrap *tdbd = NULL;
-
-/* the key type used in the unexpected packet database */
-struct unexpected_key {
-       enum packet_type packet_type;
-       time_t timestamp;
-       int count;
-};
-
-struct pending_unexpected {
-       struct pending_unexpected *prev, *next;
-       enum packet_type packet_type;
-       int id;
-       time_t timeout;
-};
-
-static struct pending_unexpected *pu_list;
-
-/****************************************************************************
- This function is called when nmbd has received an unexpected packet.
- It checks against the list of outstanding packet transaction id's
- to see if it should be stored in the unexpected.tdb.
-**************************************************************************/
-
-static struct pending_unexpected *find_unexpected_packet(struct packet_struct *p)
-{
-       struct pending_unexpected *pu;
-
-       if (!p) {
-               return NULL;
-       }
-
-       for (pu = pu_list; pu; pu = pu->next) {
-               if (pu->packet_type == p->packet_type) {
-                       int id = (p->packet_type == DGRAM_PACKET) ?
-                               p->packet.dgram.header.dgm_id :
-                               p->packet.nmb.header.name_trn_id;
-                       if (id == pu->id) {
-                               DEBUG(10,("find_unexpected_packet: found packet "
-                                       "with id = %d\n", pu->id ));
-                               return pu;
-                       }
-               }
-       }
-
-       return NULL;
-}
-
-
-/****************************************************************************
- This function is called when nmbd has been given a packet to send out.
- It stores a list of outstanding packet transaction id's and the timeout
- when they should be removed.
-**************************************************************************/
-
-bool store_outstanding_send_packet(struct packet_struct *p)
-{
-       struct pending_unexpected *pu = NULL;
-
-       if (!p) {
-               return false;
-       }
-
-       pu = find_unexpected_packet(p);
-       if (pu) {
-               /* This is a resend, and we haven't received a
-                  reply yet ! Ignore it. */
-               return false;
-       }
-
-       pu = SMB_MALLOC_P(struct pending_unexpected);
-       if (!pu || !p) {
-               return false;
-       }
-
-       ZERO_STRUCTP(pu);
-       pu->packet_type = p->packet_type;
-       pu->id = (p->packet_type == DGRAM_PACKET) ?
-                       p->packet.dgram.header.dgm_id :
-                       p->packet.nmb.header.name_trn_id;
-       pu->timeout = time(NULL) + 15;
-
-       DLIST_ADD_END(pu_list, pu, struct pending_unexpected *);
-
-       DEBUG(10,("store_outstanding_unexpected_packet: storing packet "
-               "with id = %d\n", pu->id ));
-
-       return true;
-}
-
-/****************************************************************************
- Return true if this is a reply to a packet we were requested to send.
-**************************************************************************/
-
-bool is_requested_send_packet(struct packet_struct *p)
-{
-       return (find_unexpected_packet(p) != NULL);
-}
-
-/****************************************************************************
- This function is called when nmbd has received an unexpected packet.
- It checks against the list of outstanding packet transaction id's
- to see if it should be stored in the unexpected.tdb. Don't store if
- not found.
-**************************************************************************/
-
-static bool should_store_unexpected_packet(struct packet_struct *p)
-{
-       struct pending_unexpected *pu = find_unexpected_packet(p);
-
-       if (!pu) {
-               return false;
-       }
-
-       /* Remove the outstanding entry. */
-       DLIST_REMOVE(pu_list, pu);
-       SAFE_FREE(pu);
-       return true;
-}
-
-/****************************************************************************
- All unexpected packets are passed in here, to be stored in a unexpected
- packet database. This allows nmblookup and other tools to receive packets
- erroneously sent to the wrong port by broken MS systems.
-**************************************************************************/
-
-void unexpected_packet(struct packet_struct *p)
-{
-       static int count;
-       TDB_DATA kbuf, dbuf;
-       struct unexpected_key key;
-       char buf[1024];
-       int len=0;
-       uint32_t enc_ip;
-
-       if (!should_store_unexpected_packet(p)) {
-               DEBUG(10,("Not storing unexpected packet\n"));
-               return;
-       }
-
-       DEBUG(10,("unexpected_packet: storing packet\n"));
-
-       if (!tdbd) {
-               tdbd = tdb_wrap_open(NULL, lock_path("unexpected.tdb"), 0,
-                                    TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
-                                    O_RDWR | O_CREAT, 0644);
-               if (!tdbd) {
-                       DEBUG(0,("Failed to open unexpected.tdb\n"));
-                       return;
-               }
-       }
-
-       memset(buf,'\0',sizeof(buf));
-
-       /* Encode the ip addr and port. */
-       enc_ip = ntohl(p->ip.s_addr);
-       SIVAL(buf,0,enc_ip);
-       SSVAL(buf,4,p->port);
-
-       len = build_packet(&buf[6], sizeof(buf)-6, p) + 6;
-
-       ZERO_STRUCT(key);       /* needed for potential alignment */
-
-       key.packet_type = p->packet_type;
-       key.timestamp = p->timestamp;
-       key.count = count++;
-
-       kbuf.dptr = (uint8_t *)&key;
-       kbuf.dsize = sizeof(key);
-       dbuf.dptr = (uint8_t *)buf;
-       dbuf.dsize = len;
-
-       tdb_store(tdbd->tdb, kbuf, dbuf, TDB_REPLACE);
-}
-
-
-static time_t lastt;
-
-/****************************************************************************
- Delete the record if it is too old.
-**************************************************************************/
-
-static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
-{
-       struct unexpected_key key;
-
-       if (kbuf.dsize != sizeof(key)) {
-               tdb_delete(ttdb, kbuf);
-       }
-
-       memcpy(&key, kbuf.dptr, sizeof(key));
-
-       if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
-               tdb_delete(ttdb, kbuf);
-       }
-
-       return 0;
-}
-
-
-/****************************************************************************
- Delete all old unexpected packets.
-**************************************************************************/
-
-void clear_unexpected(time_t t)
-{
-       struct pending_unexpected *pu, *pu_next;
-
-       for (pu = pu_list; pu; pu = pu_next) {
-               pu_next = pu->next;
-               if (pu->timeout < t) {
-                       DLIST_REMOVE(pu_list, pu);
-                       SAFE_FREE(pu);
-               }
-       }
-
-       if (!tdbd) return;
-
-       if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
-               return;
-
-       lastt = t;
-
-       tdb_traverse(tdbd->tdb, traverse_fn, NULL);
-}
-
-struct receive_unexpected_state {
-       struct packet_struct *matched_packet;
-       int match_id;
-       enum packet_type match_type;
-       const char *match_name;
-};
-
-/****************************************************************************
- tdb traversal fn to find a matching 137 packet.
-**************************************************************************/
-
-static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
-                         void *private_data)
-{
-       struct receive_unexpected_state *state =
-               (struct receive_unexpected_state *)private_data;
-       struct unexpected_key key;
-       struct in_addr ip;
-       uint32_t enc_ip;
-       int port;
-       struct packet_struct *p;
-
-       if (kbuf.dsize != sizeof(key)) {
-               return 0;
-       }
-
-       memcpy(&key, kbuf.dptr, sizeof(key));
-
-       if (key.packet_type != state->match_type) return 0;
-
-       if (dbuf.dsize < 6) {
-               return 0;
-       }
-
-       /* Decode the ip addr and port. */
-       enc_ip = IVAL(dbuf.dptr,0);
-       ip.s_addr = htonl(enc_ip);
-       port = SVAL(dbuf.dptr,4);
-
-       p = parse_packet((char *)&dbuf.dptr[6],
-                       dbuf.dsize-6,
-                       state->match_type,
-                       ip,
-                       port);
-       if (!p)
-               return 0;
-
-       if ((state->match_type == NMB_PACKET &&
-            p->packet.nmb.header.name_trn_id == state->match_id) ||
-           (state->match_type == DGRAM_PACKET &&
-            match_mailslot_name(p, state->match_name) &&
-            p->packet.dgram.header.dgm_id == state->match_id)) {
-               state->matched_packet = p;
-               tdb_delete(ttdb, kbuf);
-               return -1;
-       }
-
-       free_packet(p);
-
-       return 0;
-}
-
-/****************************************************************************
- Check for a particular packet in the unexpected packet queue.
-**************************************************************************/
-
-struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
-                                        const char *mailslot_name)
-{
-       struct tdb_wrap *tdb2;
-       struct receive_unexpected_state state;
-
-       tdb2 = tdb_wrap_open(talloc_tos(), lock_path("unexpected.tdb"), 0, 0,
-                            O_RDWR, 0);
-       if (!tdb2) return NULL;
-
-       state.matched_packet = NULL;
-       state.match_id = id;
-       state.match_type = packet_type;
-       state.match_name = mailslot_name;
-
-       tdb_traverse(tdb2->tdb, traverse_match, &state);
-
-       TALLOC_FREE(tdb2);
-
-       return state.matched_packet;
-}
+#include "libsmb/nmblib.h"
 
 static const char *nmbd_socket_dir(void)
 {
-       return lp_parm_const_string(-1, "nmbd", "socket dir", "/tmp/.nmbd");
+       return lp_parm_const_string(-1, "nmbd", "socket dir",
+                                   get_dyn_NMBDSOCKETDIR());
 }
 
 struct nb_packet_query {
@@ -383,8 +72,9 @@ NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
        struct nb_packet_server *result;
        struct tevent_fd *fde;
        NTSTATUS status;
+       int rc;
 
-       result = TALLOC_ZERO_P(mem_ctx, struct nb_packet_server);
+       result = talloc_zero(mem_ctx, struct nb_packet_server);
        if (result == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto fail;
@@ -398,6 +88,11 @@ NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
                status = map_nt_error_from_unix(errno);
                goto fail;
        }
+       rc = listen(result->listen_sock, 5);
+       if (rc < 0) {
+               status = map_nt_error_from_unix(errno);
+               goto fail;
+       }
        talloc_set_destructor(result, nb_packet_server_destructor);
 
        fde = tevent_add_fd(ev, result, result->listen_sock, TEVENT_FD_READ,
@@ -451,7 +146,7 @@ static void nb_packet_server_listener(struct tevent_context *ev,
        }
        DEBUG(6,("accepted socket %d\n", sock));
 
-       client = TALLOC_ZERO_P(server, struct nb_packet_client);
+       client = talloc_zero(server, struct nb_packet_client);
        if (client == NULL) {
                DEBUG(10, ("talloc failed\n"));
                close(sock);
@@ -481,6 +176,15 @@ static void nb_packet_server_listener(struct tevent_context *ev,
 
        DLIST_ADD(server->clients, client);
        server->num_clients += 1;
+
+       if (server->num_clients > server->max_clients) {
+               DEBUG(10, ("Too many clients, dropping oldest\n"));
+
+               /*
+                * no TALLOC_FREE here, don't mess with the list structs
+                */
+               talloc_free(server->clients->prev);
+       }
 }
 
 static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
@@ -523,7 +227,7 @@ static void nb_packet_got_query(struct tevent_req *req)
 
        nread = read_packet_recv(req, talloc_tos(), &buf, &err);
        TALLOC_FREE(req);
-       if (nread < sizeof(struct nb_packet_query)) {
+       if (nread < (ssize_t)sizeof(struct nb_packet_query)) {
                DEBUG(10, ("read_packet_recv returned %d (%s)\n",
                           (int)nread,
                           (nread == -1) ? strerror(err) : "wrong length"));
@@ -672,7 +376,15 @@ static void nb_packet_client_send(struct nb_packet_client *client,
        struct nb_packet_client_state *state;
        struct tevent_req *req;
 
-       state = TALLOC_ZERO_P(client, struct nb_packet_client_state);
+       if (tevent_queue_length(client->out_queue) > 10) {
+               /*
+                * Skip clients that don't listen anyway, some form of DoS
+                * protection
+                */
+               return;
+       }
+
+       state = talloc_zero(client, struct nb_packet_client_state);
        if (state == NULL) {
                DEBUG(10, ("talloc failed\n"));
                return;
@@ -686,7 +398,7 @@ static void nb_packet_client_send(struct nb_packet_client *client,
        state->hdr.type = p->packet_type;
        state->hdr.len = build_packet(state->buf, sizeof(state->buf), p);
 
-       state->iov[0].iov_base = &state->hdr;
+       state->iov[0].iov_base = (char *)&state->hdr;
        state->iov[0].iov_len = sizeof(state->hdr);
        state->iov[1].iov_base = state->buf;
        state->iov[1].iov_len = state->hdr.len;
@@ -779,7 +491,7 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
                state->query.mailslot_namelen = strlen(mailslot_name);
        }
 
-       state->reader = TALLOC_ZERO_P(state, struct nb_packet_reader);
+       state->reader = talloc_zero(state, struct nb_packet_reader);
        if (tevent_req_nomem(state->reader, req)) {
                return tevent_req_post(req, ev);
        }
@@ -802,7 +514,7 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
 
        subreq = async_connect_send(state, ev, state->reader->sock,
                                    (struct sockaddr *)(void *)&state->addr,
-                                   sizeof(state->addr));
+                                   sizeof(state->addr), NULL, NULL, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -836,7 +548,7 @@ static void nb_packet_reader_connected(struct tevent_req *subreq)
                return;
        }
 
-       state->iov[0].iov_base = &state->query;
+       state->iov[0].iov_base = (char *)&state->query;
        state->iov[0].iov_len = sizeof(state->query);
 
        if (state->mailslot_name != NULL) {