s3: Convert unexpected.tdb to use tdb_wrap_open
[sfrench/samba-autobuild/.git] / source3 / libsmb / unexpected.c
1 /*
2    Unix SMB/CIFS implementation.
3    handle unexpected packets
4    Copyright (C) Andrew Tridgell 2000
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
21 #include "includes.h"
22
23 static struct tdb_wrap *tdbd = NULL;
24
25 /* the key type used in the unexpected packet database */
26 struct unexpected_key {
27         enum packet_type packet_type;
28         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_wrap_open(talloc_autofree_context(),
49                                      lock_path("unexpected.tdb"), 0,
50                                      TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
51                                      O_RDWR | O_CREAT, 0644);
52                 if (!tdbd) {
53                         DEBUG(0,("Failed to open unexpected.tdb\n"));
54                         return;
55                 }
56         }
57
58         memset(buf,'\0',sizeof(buf));
59
60         /* Encode the ip addr and port. */
61         enc_ip = ntohl(p->ip.s_addr);
62         SIVAL(buf,0,enc_ip);
63         SSVAL(buf,4,p->port);
64
65         len = build_packet(&buf[6], sizeof(buf)-6, p) + 6;
66
67         ZERO_STRUCT(key);       /* needed for potential alignment */
68
69         key.packet_type = p->packet_type;
70         key.timestamp = p->timestamp;
71         key.count = count++;
72
73         kbuf.dptr = (uint8_t *)&key;
74         kbuf.dsize = sizeof(key);
75         dbuf.dptr = (uint8_t *)buf;
76         dbuf.dsize = len;
77
78         tdb_store(tdbd->tdb, kbuf, dbuf, TDB_REPLACE);
79 }
80
81
82 static time_t lastt;
83
84 /****************************************************************************
85  Delete the record if it is too old.
86 **************************************************************************/
87
88 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
89 {
90         struct unexpected_key key;
91
92         if (kbuf.dsize != sizeof(key)) {
93                 tdb_delete(ttdb, kbuf);
94         }
95
96         memcpy(&key, kbuf.dptr, sizeof(key));
97
98         if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
99                 tdb_delete(ttdb, kbuf);
100         }
101
102         return 0;
103 }
104
105
106 /****************************************************************************
107  Delete all old unexpected packets.
108 **************************************************************************/
109
110 void clear_unexpected(time_t t)
111 {
112         if (!tdbd) return;
113
114         if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
115                 return;
116
117         lastt = t;
118
119         tdb_traverse(tdbd->tdb, traverse_fn, NULL);
120 }
121
122 struct receive_unexpected_state {
123         struct packet_struct *matched_packet;
124         int match_id;
125         enum packet_type match_type;
126         const char *match_name;
127 };
128
129 /****************************************************************************
130  tdb traversal fn to find a matching 137 packet.
131 **************************************************************************/
132
133 static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
134                           void *private_data)
135 {
136         struct receive_unexpected_state *state =
137                 (struct receive_unexpected_state *)private_data;
138         struct unexpected_key key;
139         struct in_addr ip;
140         uint32_t enc_ip;
141         int port;
142         struct packet_struct *p;
143
144         if (kbuf.dsize != sizeof(key)) {
145                 return 0;
146         }
147
148         memcpy(&key, kbuf.dptr, sizeof(key));
149
150         if (key.packet_type != state->match_type) return 0;
151
152         if (dbuf.dsize < 6) {
153                 return 0;
154         }
155
156         /* Decode the ip addr and port. */
157         enc_ip = IVAL(dbuf.dptr,0);
158         ip.s_addr = htonl(enc_ip);
159         port = SVAL(dbuf.dptr,4);
160
161         p = parse_packet((char *)&dbuf.dptr[6],
162                         dbuf.dsize-6,
163                         state->match_type,
164                         ip,
165                         port);
166         if (!p)
167                 return 0;
168
169         if ((state->match_type == NMB_PACKET &&
170              p->packet.nmb.header.name_trn_id == state->match_id) ||
171             (state->match_type == DGRAM_PACKET &&
172              match_mailslot_name(p, state->match_name))) {
173                 state->matched_packet = p;
174                 return -1;
175         }
176
177         free_packet(p);
178
179         return 0;
180 }
181
182 /****************************************************************************
183  Check for a particular packet in the unexpected packet queue.
184 **************************************************************************/
185
186 struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
187                                          const char *mailslot_name)
188 {
189         struct tdb_wrap *tdb2;
190         struct receive_unexpected_state state;
191
192         tdb2 = tdb_wrap_open(talloc_autofree_context(),
193                              lock_path("unexpected.tdb"), 0, 0, O_RDONLY, 0);
194         if (!tdb2) return NULL;
195
196         state.matched_packet = NULL;
197         state.match_id = id;
198         state.match_type = packet_type;
199         state.match_name = mailslot_name;
200
201         tdb_traverse(tdb2->tdb, traverse_match, &state);
202
203         TALLOC_FREE(tdb2);
204
205         return state.matched_packet;
206 }