talloc: Bump version number after pytalloc changes.
[Samba.git] / source3 / libsmb / unexpected.c
blob0f4227de1657253553464ec5ce47a2829bf4bc03
1 /*
2 Unix SMB/CIFS implementation.
3 handle unexpected packets
4 Copyright (C) Andrew Tridgell 2000
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.
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.
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/>.
21 #include "includes.h"
23 static struct tdb_wrap *tdbd = NULL;
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;
32 struct pending_unexpected {
33 struct pending_unexpected *prev, *next;
34 enum packet_type packet_type;
35 int id;
36 time_t timeout;
39 static struct pending_unexpected *pu_list;
41 /****************************************************************************
42 This function is called when nmbd has received an unexpected packet.
43 It checks against the list of outstanding packet transaction id's
44 to see if it should be stored in the unexpected.tdb.
45 **************************************************************************/
47 static struct pending_unexpected *find_unexpected_packet(struct packet_struct *p)
49 struct pending_unexpected *pu;
51 if (!p) {
52 return NULL;
55 for (pu = pu_list; pu; pu = pu->next) {
56 if (pu->packet_type == p->packet_type) {
57 int id = (p->packet_type == DGRAM_PACKET) ?
58 p->packet.dgram.header.dgm_id :
59 p->packet.nmb.header.name_trn_id;
60 if (id == pu->id) {
61 DEBUG(10,("find_unexpected_packet: found packet "
62 "with id = %d\n", pu->id ));
63 return pu;
68 return NULL;
72 /****************************************************************************
73 This function is called when nmbd has been given a packet to send out.
74 It stores a list of outstanding packet transaction id's and the timeout
75 when they should be removed.
76 **************************************************************************/
78 bool store_outstanding_send_packet(struct packet_struct *p)
80 struct pending_unexpected *pu = NULL;
82 if (!p) {
83 return false;
86 pu = find_unexpected_packet(p);
87 if (pu) {
88 /* This is a resend, and we haven't received a
89 reply yet ! Ignore it. */
90 return false;
93 pu = SMB_MALLOC_P(struct pending_unexpected);
94 if (!pu || !p) {
95 return false;
98 ZERO_STRUCTP(pu);
99 pu->packet_type = p->packet_type;
100 pu->id = (p->packet_type == DGRAM_PACKET) ?
101 p->packet.dgram.header.dgm_id :
102 p->packet.nmb.header.name_trn_id;
103 pu->timeout = time(NULL) + 15;
105 DLIST_ADD_END(pu_list, pu, struct pending_unexpected *);
107 DEBUG(10,("store_outstanding_unexpected_packet: storing packet "
108 "with id = %d\n", pu->id ));
110 return true;
113 /****************************************************************************
114 Return true if this is a reply to a packet we were requested to send.
115 **************************************************************************/
117 bool is_requested_send_packet(struct packet_struct *p)
119 return (find_unexpected_packet(p) != NULL);
122 /****************************************************************************
123 This function is called when nmbd has received an unexpected packet.
124 It checks against the list of outstanding packet transaction id's
125 to see if it should be stored in the unexpected.tdb. Don't store if
126 not found.
127 **************************************************************************/
129 static bool should_store_unexpected_packet(struct packet_struct *p)
131 struct pending_unexpected *pu = find_unexpected_packet(p);
133 if (!pu) {
134 return false;
137 /* Remove the outstanding entry. */
138 DLIST_REMOVE(pu_list, pu);
139 SAFE_FREE(pu);
140 return true;
143 /****************************************************************************
144 All unexpected packets are passed in here, to be stored in a unexpected
145 packet database. This allows nmblookup and other tools to receive packets
146 erroneously sent to the wrong port by broken MS systems.
147 **************************************************************************/
149 void unexpected_packet(struct packet_struct *p)
151 static int count;
152 TDB_DATA kbuf, dbuf;
153 struct unexpected_key key;
154 char buf[1024];
155 int len=0;
156 uint32_t enc_ip;
158 if (!should_store_unexpected_packet(p)) {
159 DEBUG(10,("Not storing unexpected packet\n"));
160 return;
163 DEBUG(10,("unexpected_packet: storing packet\n"));
165 if (!tdbd) {
166 tdbd = tdb_wrap_open(NULL, lock_path("unexpected.tdb"), 0,
167 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
168 O_RDWR | O_CREAT, 0644);
169 if (!tdbd) {
170 DEBUG(0,("Failed to open unexpected.tdb\n"));
171 return;
175 memset(buf,'\0',sizeof(buf));
177 /* Encode the ip addr and port. */
178 enc_ip = ntohl(p->ip.s_addr);
179 SIVAL(buf,0,enc_ip);
180 SSVAL(buf,4,p->port);
182 len = build_packet(&buf[6], sizeof(buf)-6, p) + 6;
184 ZERO_STRUCT(key); /* needed for potential alignment */
186 key.packet_type = p->packet_type;
187 key.timestamp = p->timestamp;
188 key.count = count++;
190 kbuf.dptr = (uint8_t *)&key;
191 kbuf.dsize = sizeof(key);
192 dbuf.dptr = (uint8_t *)buf;
193 dbuf.dsize = len;
195 tdb_store(tdbd->tdb, kbuf, dbuf, TDB_REPLACE);
199 static time_t lastt;
201 /****************************************************************************
202 Delete the record if it is too old.
203 **************************************************************************/
205 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
207 struct unexpected_key key;
209 if (kbuf.dsize != sizeof(key)) {
210 tdb_delete(ttdb, kbuf);
213 memcpy(&key, kbuf.dptr, sizeof(key));
215 if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
216 tdb_delete(ttdb, kbuf);
219 return 0;
223 /****************************************************************************
224 Delete all old unexpected packets.
225 **************************************************************************/
227 void clear_unexpected(time_t t)
229 struct pending_unexpected *pu, *pu_next;
231 for (pu = pu_list; pu; pu = pu_next) {
232 pu_next = pu->next;
233 if (pu->timeout < t) {
234 DLIST_REMOVE(pu_list, pu);
238 if (!tdbd) return;
240 if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
241 return;
243 lastt = t;
245 tdb_traverse(tdbd->tdb, traverse_fn, NULL);
248 struct receive_unexpected_state {
249 struct packet_struct *matched_packet;
250 int match_id;
251 enum packet_type match_type;
252 const char *match_name;
255 /****************************************************************************
256 tdb traversal fn to find a matching 137 packet.
257 **************************************************************************/
259 static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
260 void *private_data)
262 struct receive_unexpected_state *state =
263 (struct receive_unexpected_state *)private_data;
264 struct unexpected_key key;
265 struct in_addr ip;
266 uint32_t enc_ip;
267 int port;
268 struct packet_struct *p;
270 if (kbuf.dsize != sizeof(key)) {
271 return 0;
274 memcpy(&key, kbuf.dptr, sizeof(key));
276 if (key.packet_type != state->match_type) return 0;
278 if (dbuf.dsize < 6) {
279 return 0;
282 /* Decode the ip addr and port. */
283 enc_ip = IVAL(dbuf.dptr,0);
284 ip.s_addr = htonl(enc_ip);
285 port = SVAL(dbuf.dptr,4);
287 p = parse_packet((char *)&dbuf.dptr[6],
288 dbuf.dsize-6,
289 state->match_type,
291 port);
292 if (!p)
293 return 0;
295 if ((state->match_type == NMB_PACKET &&
296 p->packet.nmb.header.name_trn_id == state->match_id) ||
297 (state->match_type == DGRAM_PACKET &&
298 match_mailslot_name(p, state->match_name) &&
299 p->packet.dgram.header.dgm_id == state->match_id)) {
300 state->matched_packet = p;
301 tdb_delete(ttdb, kbuf);
302 return -1;
305 free_packet(p);
307 return 0;
310 /****************************************************************************
311 Check for a particular packet in the unexpected packet queue.
312 **************************************************************************/
314 struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
315 const char *mailslot_name)
317 struct tdb_wrap *tdb2;
318 struct receive_unexpected_state state;
320 tdb2 = tdb_wrap_open(talloc_tos(), lock_path("unexpected.tdb"), 0, 0,
321 O_RDWR, 0);
322 if (!tdb2) return NULL;
324 state.matched_packet = NULL;
325 state.match_id = id;
326 state.match_type = packet_type;
327 state.match_name = mailslot_name;
329 tdb_traverse(tdb2->tdb, traverse_match, &state);
331 TALLOC_FREE(tdb2);
333 return state.matched_packet;