Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : NBT netbios routines and daemon - version 2
4 :
5 : Copyright (C) Jeremy Allison 1994-2005
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 :
20 : Converted to store WINS data in a tdb. Dec 2005. JRA.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include "nmbd/nmbd.h"
26 : #include "util_tdb.h"
27 :
28 : #define WINS_LIST "wins.dat"
29 : #define WINS_VERSION 1
30 : #define WINSDB_VERSION 1
31 :
32 : /****************************************************************************
33 : We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
34 : name (65 bytes with the last byte being the name type).
35 : *****************************************************************************/
36 :
37 : TDB_CONTEXT *wins_tdb;
38 :
39 : /****************************************************************************
40 : Delete all the temporary name records on the in-memory linked list.
41 : *****************************************************************************/
42 :
43 0 : static void wins_delete_all_tmp_in_memory_records(void)
44 : {
45 0 : struct name_record *nr = NULL;
46 0 : struct name_record *nrnext = NULL;
47 :
48 : /* Delete all temporary name records on the wins subnet linked list. */
49 0 : for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
50 0 : nrnext = nr->next;
51 0 : DLIST_REMOVE(wins_server_subnet->namelist, nr);
52 0 : SAFE_FREE(nr->data.ip);
53 0 : SAFE_FREE(nr);
54 : }
55 0 : }
56 :
57 : /****************************************************************************
58 : Delete all the temporary 1b name records on the in-memory linked list.
59 : *****************************************************************************/
60 :
61 0 : static void wins_delete_all_1b_in_memory_records(void)
62 : {
63 0 : struct name_record *nr = NULL;
64 0 : struct name_record *nrnext = NULL;
65 :
66 : /* Delete all temporary 1b name records on the wins subnet linked list. */
67 0 : for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
68 0 : nrnext = nr->next;
69 0 : if (nr->name.name_type == 0x1b) {
70 0 : DLIST_REMOVE(wins_server_subnet->namelist, nr);
71 0 : SAFE_FREE(nr->data.ip);
72 0 : SAFE_FREE(nr);
73 : }
74 : }
75 0 : }
76 :
77 : /****************************************************************************
78 : Convert a wins.tdb record to a struct name_record. Add in our lp_netbios_scope().
79 : *****************************************************************************/
80 :
81 0 : static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
82 : {
83 0 : struct name_record *namerec = NULL;
84 : uint16_t nb_flags;
85 : unsigned char nr_src;
86 : uint32_t death_time, refresh_time;
87 : uint32_t id_low, id_high;
88 : uint32_t saddr;
89 : uint32_t wins_flags;
90 : uint32_t num_ips;
91 : size_t len;
92 : int i;
93 :
94 0 : if (data.dptr == NULL || data.dsize == 0) {
95 0 : return NULL;
96 : }
97 :
98 : /* Min size is "wbddddddd" + 1 ip address (4). */
99 0 : if (data.dsize < 2 + 1 + (7*4) + 4) {
100 0 : return NULL;
101 : }
102 :
103 0 : len = tdb_unpack(data.dptr, data.dsize,
104 : "wbddddddd",
105 : &nb_flags,
106 : &nr_src,
107 : &death_time,
108 : &refresh_time,
109 : &id_low,
110 : &id_high,
111 : &saddr,
112 : &wins_flags,
113 : &num_ips );
114 :
115 0 : namerec = SMB_MALLOC_P(struct name_record);
116 0 : if (!namerec) {
117 0 : return NULL;
118 : }
119 0 : ZERO_STRUCTP(namerec);
120 :
121 0 : namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
122 0 : if (!namerec->data.ip) {
123 0 : SAFE_FREE(namerec);
124 0 : return NULL;
125 : }
126 :
127 0 : namerec->subnet = wins_server_subnet;
128 0 : push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
129 0 : namerec->name.name_type = key.dptr[sizeof(unstring)];
130 : /* Add the scope. */
131 0 : push_ascii(namerec->name.scope, lp_netbios_scope(), 64, STR_TERMINATE);
132 :
133 : /* We're using a byte-by-byte compare, so we must be sure that
134 : * unused space doesn't have garbage in it.
135 : */
136 :
137 0 : for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
138 0 : namerec->name.name[i] = '\0';
139 : }
140 0 : for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
141 0 : namerec->name.scope[i] = '\0';
142 : }
143 :
144 0 : namerec->data.nb_flags = nb_flags;
145 0 : namerec->data.source = (enum name_source)nr_src;
146 0 : namerec->data.death_time = (time_t)death_time;
147 0 : namerec->data.refresh_time = (time_t)refresh_time;
148 0 : namerec->data.id = id_low;
149 0 : namerec->data.id |= ((uint64_t)id_high << 32);
150 0 : namerec->data.wins_ip.s_addr = saddr;
151 0 : namerec->data.wins_flags = wins_flags,
152 0 : namerec->data.num_ips = num_ips;
153 :
154 0 : for (i = 0; i < num_ips; i++) {
155 0 : namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
156 : }
157 :
158 0 : return namerec;
159 : }
160 :
161 : /****************************************************************************
162 : Convert a struct name_record to a wins.tdb record. Ignore the scope.
163 : *****************************************************************************/
164 :
165 0 : static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
166 : {
167 : TDB_DATA data;
168 0 : size_t len = 0;
169 : int i;
170 0 : uint32_t id_low = (namerec->data.id & 0xFFFFFFFF);
171 0 : uint32_t id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
172 :
173 0 : ZERO_STRUCT(data);
174 :
175 0 : len = (2 + 1 + (7*4)); /* "wbddddddd" */
176 0 : len += (namerec->data.num_ips * 4);
177 :
178 0 : data.dptr = (uint8_t *)SMB_MALLOC(len);
179 0 : if (!data.dptr) {
180 0 : return data;
181 : }
182 0 : data.dsize = len;
183 :
184 0 : len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
185 0 : namerec->data.nb_flags,
186 0 : (unsigned char)namerec->data.source,
187 0 : (uint32_t)namerec->data.death_time,
188 0 : (uint32_t)namerec->data.refresh_time,
189 : id_low,
190 : id_high,
191 0 : (uint32_t)namerec->data.wins_ip.s_addr,
192 0 : (uint32_t)namerec->data.wins_flags,
193 0 : (uint32_t)namerec->data.num_ips );
194 :
195 0 : for (i = 0; i < namerec->data.num_ips; i++) {
196 0 : SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
197 : }
198 :
199 0 : return data;
200 : }
201 :
202 : /****************************************************************************
203 : Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
204 : *****************************************************************************/
205 :
206 0 : static TDB_DATA name_to_key(const struct nmb_name *nmbname)
207 : {
208 : static char keydata[sizeof(unstring) + 1];
209 : TDB_DATA key;
210 :
211 0 : memset(keydata, '\0', sizeof(keydata));
212 :
213 0 : pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
214 0 : (void)strupper_m(keydata);
215 0 : keydata[sizeof(unstring)] = nmbname->name_type;
216 0 : key.dptr = (uint8_t *)keydata;
217 0 : key.dsize = sizeof(keydata);
218 :
219 0 : return key;
220 : }
221 :
222 : /****************************************************************************
223 : Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
224 : on the linked list. We will free this later in XXXX().
225 : *****************************************************************************/
226 :
227 0 : struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
228 : {
229 : TDB_DATA data, key;
230 0 : struct name_record *nr = NULL;
231 0 : struct name_record *namerec = NULL;
232 :
233 0 : if (!wins_tdb) {
234 0 : return NULL;
235 : }
236 :
237 0 : key = name_to_key(nmbname);
238 0 : data = tdb_fetch(wins_tdb, key);
239 :
240 0 : if (data.dsize == 0) {
241 0 : return NULL;
242 : }
243 :
244 0 : namerec = wins_record_to_name_record(key, data);
245 :
246 : /* done with the this */
247 :
248 0 : SAFE_FREE( data.dptr );
249 :
250 0 : if (!namerec) {
251 0 : return NULL;
252 : }
253 :
254 : /* Self names only - these include permanent names. */
255 0 : if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
256 0 : DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
257 0 : SAFE_FREE(namerec->data.ip);
258 0 : SAFE_FREE(namerec);
259 0 : return NULL;
260 : }
261 :
262 : /* Search for this name record on the list. Replace it if found. */
263 :
264 0 : for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
265 0 : if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
266 : /* Delete it. */
267 0 : DLIST_REMOVE(wins_server_subnet->namelist, nr);
268 0 : SAFE_FREE(nr->data.ip);
269 0 : SAFE_FREE(nr);
270 0 : break;
271 : }
272 : }
273 :
274 0 : DLIST_ADD(wins_server_subnet->namelist, namerec);
275 0 : return namerec;
276 : }
277 :
278 : /****************************************************************************
279 : Overwrite or add a given name in the wins.tdb.
280 : *****************************************************************************/
281 :
282 0 : static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
283 : {
284 : TDB_DATA key, data;
285 : int ret;
286 :
287 0 : if (!wins_tdb) {
288 0 : return False;
289 : }
290 :
291 0 : key = name_to_key(&namerec->name);
292 0 : data = name_record_to_wins_record(namerec);
293 :
294 0 : if (data.dptr == NULL) {
295 0 : return False;
296 : }
297 :
298 0 : ret = tdb_store(wins_tdb, key, data, tdb_flag);
299 :
300 0 : SAFE_FREE(data.dptr);
301 0 : return (ret == 0) ? True : False;
302 : }
303 :
304 : /****************************************************************************
305 : Overwrite a given name in the wins.tdb.
306 : *****************************************************************************/
307 :
308 0 : bool wins_store_changed_namerec(const struct name_record *namerec)
309 : {
310 0 : return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
311 : }
312 :
313 : /****************************************************************************
314 : Primary interface into creating and overwriting records in the wins.tdb.
315 : *****************************************************************************/
316 :
317 0 : bool add_name_to_wins_subnet(const struct name_record *namerec)
318 : {
319 0 : return store_or_replace_wins_namerec(namerec, TDB_INSERT);
320 : }
321 :
322 : /****************************************************************************
323 : Delete a given name in the tdb and remove the temporary malloc'ed data struct
324 : on the linked list.
325 : *****************************************************************************/
326 :
327 0 : bool remove_name_from_wins_namelist(struct name_record *namerec)
328 : {
329 : TDB_DATA key;
330 : int ret;
331 :
332 0 : if (!wins_tdb) {
333 0 : return False;
334 : }
335 :
336 0 : key = name_to_key(&namerec->name);
337 0 : ret = tdb_delete(wins_tdb, key);
338 :
339 0 : DLIST_REMOVE(wins_server_subnet->namelist, namerec);
340 :
341 : /* namerec must be freed by the caller */
342 :
343 0 : return (ret == 0) ? True : False;
344 : }
345 :
346 : /****************************************************************************
347 : Dump out the complete namelist.
348 : *****************************************************************************/
349 :
350 0 : static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
351 : {
352 0 : struct name_record *namerec = NULL;
353 0 : FILE *fp = (FILE *)state;
354 :
355 0 : if (kbuf.dsize != sizeof(unstring) + 1) {
356 0 : return 0;
357 : }
358 :
359 0 : namerec = wins_record_to_name_record(kbuf, dbuf);
360 0 : if (!namerec) {
361 0 : return 0;
362 : }
363 :
364 0 : dump_name_record(namerec, fp);
365 :
366 0 : SAFE_FREE(namerec->data.ip);
367 0 : SAFE_FREE(namerec);
368 0 : return 0;
369 : }
370 :
371 0 : void dump_wins_subnet_namelist(FILE *fp)
372 : {
373 0 : tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
374 0 : }
375 :
376 : /****************************************************************************
377 : Change the wins owner address in the record.
378 : *****************************************************************************/
379 :
380 0 : static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
381 : {
382 0 : namerec->data.wins_ip=wins_ip;
383 0 : }
384 :
385 : /****************************************************************************
386 : Create the wins flags based on the nb flags and the input value.
387 : *****************************************************************************/
388 :
389 0 : static void update_wins_flag(struct name_record *namerec, int flags)
390 : {
391 0 : namerec->data.wins_flags=0x0;
392 :
393 : /* if it's a group, it can be a normal or a special one */
394 0 : if (namerec->data.nb_flags & NB_GROUP) {
395 0 : if (namerec->name.name_type==0x1C) {
396 0 : namerec->data.wins_flags|=WINS_SGROUP;
397 : } else {
398 0 : if (namerec->data.num_ips>1) {
399 0 : namerec->data.wins_flags|=WINS_SGROUP;
400 : } else {
401 0 : namerec->data.wins_flags|=WINS_NGROUP;
402 : }
403 : }
404 : } else {
405 : /* can be unique or multi-homed */
406 0 : if (namerec->data.num_ips>1) {
407 0 : namerec->data.wins_flags|=WINS_MHOMED;
408 : } else {
409 0 : namerec->data.wins_flags|=WINS_UNIQUE;
410 : }
411 : }
412 :
413 : /* the node type are the same bits */
414 0 : namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
415 :
416 : /* the static bit is elsewhere */
417 0 : if (namerec->data.death_time == PERMANENT_TTL) {
418 0 : namerec->data.wins_flags|=WINS_STATIC;
419 : }
420 :
421 : /* and add the given bits */
422 0 : namerec->data.wins_flags|=flags;
423 :
424 0 : DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n",
425 : namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
426 0 : }
427 :
428 : /****************************************************************************
429 : Return the general ID value and increase it if requested.
430 : *****************************************************************************/
431 :
432 0 : static void get_global_id_and_update(uint64_t *current_id, bool update)
433 : {
434 : /*
435 : * it's kept as a static here, to prevent people from messing
436 : * with the value directly
437 : */
438 :
439 : static uint64_t general_id = 1;
440 :
441 0 : DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
442 :
443 0 : *current_id = general_id;
444 :
445 0 : if (update) {
446 0 : general_id++;
447 : }
448 0 : }
449 :
450 : /****************************************************************************
451 : Possibly call the WINS hook external program when a WINS change is made.
452 : Also stores the changed record back in the wins_tdb.
453 : *****************************************************************************/
454 :
455 0 : static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
456 : {
457 : const struct loadparm_substitution *lp_sub =
458 0 : loadparm_s3_global_substitution();
459 0 : char *command = NULL;
460 0 : char *cmd = lp_wins_hook(talloc_tos(), lp_sub);
461 : char *p, *namestr;
462 : int i;
463 0 : TALLOC_CTX *ctx = talloc_tos();
464 :
465 0 : wins_store_changed_namerec(namerec);
466 :
467 0 : if (!cmd || !*cmd) {
468 0 : return;
469 : }
470 :
471 0 : for (p=namerec->name.name; *p; p++) {
472 0 : if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
473 0 : DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
474 0 : return;
475 : }
476 : }
477 :
478 : /* Use the name without the nametype (and scope) appended */
479 :
480 0 : namestr = nmb_namestr(&namerec->name);
481 0 : if ((p = strchr(namestr, '<'))) {
482 0 : *p = 0;
483 : }
484 :
485 0 : command = talloc_asprintf(ctx,
486 : "%s %s %s %02x %d",
487 : cmd,
488 : operation,
489 : namestr,
490 : namerec->name.name_type,
491 : ttl);
492 0 : if (!command) {
493 0 : return;
494 : }
495 :
496 0 : for (i=0;i<namerec->data.num_ips;i++) {
497 0 : command = talloc_asprintf_append(command,
498 : " %s",
499 0 : inet_ntoa(namerec->data.ip[i]));
500 0 : if (!command) {
501 0 : return;
502 : }
503 : }
504 :
505 0 : DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
506 0 : smbrun(command, NULL, NULL);
507 0 : TALLOC_FREE(command);
508 : }
509 :
510 : /****************************************************************************
511 : Determine if this packet should be allocated to the WINS server.
512 : *****************************************************************************/
513 :
514 6918 : bool packet_is_for_wins_server(struct packet_struct *packet)
515 : {
516 6918 : struct nmb_packet *nmb = &packet->packet.nmb;
517 :
518 : /* Only unicast packets go to a WINS server. */
519 6918 : if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
520 6918 : DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
521 6918 : return False;
522 : }
523 :
524 : /* Check for node status requests. */
525 0 : if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
526 0 : return False;
527 : }
528 :
529 0 : switch(nmb->header.opcode) {
530 : /*
531 : * A WINS server issues WACKS, not receives them.
532 : */
533 0 : case NMB_WACK_OPCODE:
534 0 : DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
535 0 : return False;
536 : /*
537 : * A WINS server only processes registration and
538 : * release requests, not responses.
539 : */
540 0 : case NMB_NAME_REG_OPCODE:
541 : case NMB_NAME_MULTIHOMED_REG_OPCODE:
542 : case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
543 : case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
544 0 : if(nmb->header.response) {
545 0 : DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
546 0 : return False;
547 : }
548 0 : break;
549 :
550 0 : case NMB_NAME_RELEASE_OPCODE:
551 0 : if(nmb->header.response) {
552 0 : DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
553 0 : return False;
554 : }
555 0 : break;
556 :
557 : /*
558 : * Only process unicast name queries with rd = 1.
559 : */
560 0 : case NMB_NAME_QUERY_OPCODE:
561 0 : if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
562 0 : DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
563 0 : return False;
564 : }
565 0 : break;
566 : }
567 :
568 0 : return True;
569 : }
570 :
571 : /****************************************************************************
572 : Utility function to decide what ttl to give a register/refresh request.
573 : *****************************************************************************/
574 :
575 0 : static int get_ttl_from_packet(struct nmb_packet *nmb)
576 : {
577 0 : int ttl = nmb->additional->ttl;
578 :
579 0 : if (ttl < lp_min_wins_ttl()) {
580 0 : ttl = lp_min_wins_ttl();
581 : }
582 :
583 0 : if (ttl > lp_max_wins_ttl()) {
584 0 : ttl = lp_max_wins_ttl();
585 : }
586 :
587 0 : return ttl;
588 : }
589 :
590 : /****************************************************************************
591 : Load or create the WINS database.
592 : *****************************************************************************/
593 :
594 39 : bool initialise_wins(void)
595 : {
596 39 : time_t time_now = time(NULL);
597 : FILE *fp;
598 : char line[1024];
599 : char *db_path;
600 : char *list_path;
601 :
602 39 : if(!lp_we_are_a_wins_server()) {
603 39 : return True;
604 : }
605 :
606 0 : db_path = state_path(talloc_tos(), "wins.tdb");
607 0 : if (db_path == NULL) {
608 0 : return false;
609 : }
610 :
611 : /* Open the wins.tdb. */
612 0 : wins_tdb = tdb_open_log(db_path, 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
613 : O_CREAT|O_RDWR, 0600);
614 0 : TALLOC_FREE(db_path);
615 0 : if (!wins_tdb) {
616 0 : DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
617 : strerror(errno) ));
618 0 : return False;
619 : }
620 :
621 0 : tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
622 :
623 0 : add_samba_names_to_subnet(wins_server_subnet);
624 :
625 0 : list_path = state_path(talloc_tos(), WINS_LIST);
626 0 : if (list_path == NULL) {
627 0 : tdb_close(wins_tdb);
628 0 : return false;
629 : }
630 :
631 0 : fp = fopen(list_path, "r");
632 0 : TALLOC_FREE(list_path);
633 0 : if (fp == NULL) {
634 0 : DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
635 : WINS_LIST, strerror(errno) ));
636 0 : return True;
637 : }
638 :
639 0 : while (!feof(fp)) {
640 0 : char *name_str = NULL;
641 0 : char *ip_str = NULL;
642 0 : char *ttl_str = NULL, *nb_flags_str = NULL;
643 : unsigned int num_ips;
644 0 : char *name = NULL;
645 0 : struct in_addr *ip_list = NULL;
646 0 : int type = 0;
647 : int nb_flags;
648 : int ttl;
649 : const char *ptr;
650 0 : char *p = NULL;
651 : bool got_token;
652 : bool was_ip;
653 : int i;
654 : unsigned int hash;
655 : int version;
656 0 : TALLOC_CTX *frame = NULL;
657 :
658 : /* Read a line from the wins.dat file. Strips whitespace
659 : from the beginning and end of the line. */
660 0 : if (!fgets_slash(NULL, line, sizeof(line), fp)) {
661 0 : continue;
662 : }
663 :
664 0 : if (*line == '#') {
665 0 : continue;
666 : }
667 :
668 0 : if (strncmp(line,"VERSION ", 8) == 0) {
669 0 : if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
670 0 : version != WINS_VERSION) {
671 0 : DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
672 0 : fclose(fp);
673 0 : return True;
674 : }
675 0 : continue;
676 : }
677 :
678 0 : ptr = line;
679 :
680 : /*
681 : * Now we handle multiple IP addresses per name we need
682 : * to iterate over the line twice. The first time to
683 : * determine how many IP addresses there are, the second
684 : * time to actually parse them into the ip_list array.
685 : */
686 :
687 0 : frame = talloc_stackframe();
688 0 : if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
689 0 : DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
690 0 : TALLOC_FREE(frame);
691 0 : continue;
692 : }
693 :
694 0 : if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
695 0 : DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
696 0 : TALLOC_FREE(frame);
697 0 : continue;
698 : }
699 :
700 : /*
701 : * Determine the number of IP addresses per line.
702 : */
703 0 : num_ips = 0;
704 : do {
705 0 : got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
706 0 : was_ip = False;
707 :
708 0 : if(got_token && strchr(ip_str, '.')) {
709 0 : num_ips++;
710 0 : was_ip = True;
711 : }
712 0 : } while(got_token && was_ip);
713 :
714 0 : if(num_ips == 0) {
715 0 : DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
716 0 : TALLOC_FREE(frame);
717 0 : continue;
718 : }
719 :
720 0 : if(!got_token) {
721 0 : DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
722 0 : TALLOC_FREE(frame);
723 0 : continue;
724 : }
725 :
726 : /* Allocate the space for the ip_list. */
727 0 : if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
728 0 : DEBUG(0,("initialise_wins: Malloc fail !\n"));
729 0 : fclose(fp);
730 0 : TALLOC_FREE(frame);
731 0 : return False;
732 : }
733 :
734 : /* Reset and re-parse the line. */
735 0 : ptr = line;
736 0 : next_token_talloc(frame,&ptr,&name_str,NULL);
737 0 : next_token_talloc(frame,&ptr,&ttl_str,NULL);
738 0 : for(i = 0; i < num_ips; i++) {
739 0 : next_token_talloc(frame,&ptr, &ip_str, NULL);
740 0 : ip_list[i] = interpret_addr2(ip_str);
741 : }
742 0 : next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
743 :
744 : /*
745 : * Deal with SELF or REGISTER name encoding. Default is REGISTER
746 : * for compatibility with old nmbds.
747 : */
748 :
749 0 : if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
750 0 : DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
751 0 : SAFE_FREE(ip_list);
752 0 : TALLOC_FREE(frame);
753 0 : continue;
754 : }
755 :
756 0 : if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
757 0 : nb_flags_str[strlen(nb_flags_str)-1] = '\0';
758 : }
759 :
760 : /* Netbios name. # divides the name from the type (hex): netbios#xx */
761 0 : name = name_str;
762 :
763 0 : if((p = strchr(name,'#')) != NULL) {
764 0 : *p = 0;
765 0 : sscanf(p+1,"%x",&type);
766 : }
767 :
768 : /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
769 0 : sscanf(nb_flags_str,"%x",&nb_flags);
770 0 : sscanf(ttl_str,"%d",&ttl);
771 :
772 : /* add all entries that have 60 seconds or more to live */
773 0 : if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
774 0 : if(ttl != PERMANENT_TTL) {
775 0 : ttl -= time_now;
776 : }
777 :
778 0 : DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
779 : name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
780 :
781 0 : (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
782 : ttl, REGISTER_NAME, num_ips, ip_list );
783 : } else {
784 0 : DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
785 : "%s#%02x ttl = %d first IP %s flags = %2x\n",
786 : name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
787 : }
788 :
789 0 : TALLOC_FREE(frame);
790 0 : SAFE_FREE(ip_list);
791 : }
792 :
793 0 : fclose(fp);
794 0 : return True;
795 : }
796 :
797 : /****************************************************************************
798 : Send a WINS WACK (Wait ACKnowledgement) response.
799 : **************************************************************************/
800 :
801 0 : static void send_wins_wack_response(int ttl, struct packet_struct *p)
802 : {
803 0 : struct nmb_packet *nmb = &p->packet.nmb;
804 : unsigned char rdata[2];
805 :
806 0 : rdata[0] = rdata[1] = 0;
807 :
808 : /* Taken from nmblib.c - we need to send back almost
809 : identical bytes from the requesting packet header. */
810 :
811 0 : rdata[0] = (nmb->header.opcode & 0xF) << 3;
812 0 : if (nmb->header.nm_flags.authoritative && nmb->header.response) {
813 0 : rdata[0] |= 0x4;
814 : }
815 0 : if (nmb->header.nm_flags.trunc) {
816 0 : rdata[0] |= 0x2;
817 : }
818 0 : if (nmb->header.nm_flags.recursion_desired) {
819 0 : rdata[0] |= 0x1;
820 : }
821 0 : if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
822 0 : rdata[1] |= 0x80;
823 : }
824 0 : if (nmb->header.nm_flags.bcast) {
825 0 : rdata[1] |= 0x10;
826 : }
827 :
828 0 : reply_netbios_packet(p, /* Packet to reply to. */
829 : 0, /* Result code. */
830 : NMB_WAIT_ACK, /* nmbd type code. */
831 : NMB_WACK_OPCODE, /* opcode. */
832 : ttl, /* ttl. */
833 : (char *)rdata, /* data to send. */
834 : 2); /* data length. */
835 0 : }
836 :
837 : /****************************************************************************
838 : Send a WINS name registration response.
839 : **************************************************************************/
840 :
841 0 : static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
842 : {
843 0 : struct nmb_packet *nmb = &p->packet.nmb;
844 : char rdata[6];
845 :
846 0 : memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
847 :
848 0 : reply_netbios_packet(p, /* Packet to reply to. */
849 : rcode, /* Result code. */
850 : WINS_REG, /* nmbd type code. */
851 : NMB_NAME_REG_OPCODE, /* opcode. */
852 : ttl, /* ttl. */
853 : rdata, /* data to send. */
854 : 6); /* data length. */
855 0 : }
856 :
857 : /***********************************************************************
858 : Deal with a name refresh request to a WINS server.
859 : ************************************************************************/
860 :
861 0 : void wins_process_name_refresh_request( struct subnet_record *subrec,
862 : struct packet_struct *p )
863 : {
864 0 : struct nmb_packet *nmb = &p->packet.nmb;
865 0 : struct nmb_name *question = &nmb->question.question_name;
866 0 : bool bcast = nmb->header.nm_flags.bcast;
867 0 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
868 0 : bool group = (nb_flags & NB_GROUP) ? True : False;
869 0 : struct name_record *namerec = NULL;
870 0 : int ttl = get_ttl_from_packet(nmb);
871 : struct in_addr from_ip;
872 : struct in_addr our_fake_ip;
873 :
874 0 : our_fake_ip = interpret_addr2("0.0.0.0");
875 0 : putip( (char *)&from_ip, &nmb->additional->rdata[2] );
876 :
877 0 : if(bcast) {
878 : /*
879 : * We should only get unicast name refresh packets here.
880 : * Anyone trying to refresh broadcast should not be going
881 : * to a WINS server. Log an error here.
882 : */
883 0 : if( DEBUGLVL( 0 ) ) {
884 0 : dbgtext( "wins_process_name_refresh_request: " );
885 0 : dbgtext( "Broadcast name refresh request received " );
886 0 : dbgtext( "for name %s ", nmb_namestr(question) );
887 0 : dbgtext( "from IP %s ", inet_ntoa(from_ip) );
888 0 : dbgtext( "on subnet %s. ", subrec->subnet_name );
889 0 : dbgtext( "Error - Broadcasts should not be sent " );
890 0 : dbgtext( "to a WINS server\n" );
891 : }
892 0 : return;
893 : }
894 :
895 0 : if( DEBUGLVL( 3 ) ) {
896 0 : dbgtext( "wins_process_name_refresh_request: " );
897 0 : dbgtext( "Name refresh for name %s IP %s\n",
898 : nmb_namestr(question), inet_ntoa(from_ip) );
899 : }
900 :
901 : /*
902 : * See if the name already exists.
903 : * If not, handle it as a name registration and return.
904 : */
905 0 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
906 :
907 : /*
908 : * If this is a refresh request and the name doesn't exist then
909 : * treat it like a registration request. This allows us to recover
910 : * from errors (tridge)
911 : */
912 0 : if(namerec == NULL) {
913 0 : if( DEBUGLVL( 3 ) ) {
914 0 : dbgtext( "wins_process_name_refresh_request: " );
915 0 : dbgtext( "Name refresh for name %s ",
916 : nmb_namestr( question ) );
917 0 : dbgtext( "and the name does not exist. Treating " );
918 0 : dbgtext( "as registration.\n" );
919 : }
920 0 : wins_process_name_registration_request(subrec,p);
921 0 : return;
922 : }
923 :
924 : /*
925 : * if the name is present but not active, simply remove it
926 : * and treat the refresh request as a registration & return.
927 : */
928 0 : if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
929 0 : if( DEBUGLVL( 5 ) ) {
930 0 : dbgtext( "wins_process_name_refresh_request: " );
931 0 : dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
932 0 : dbgtext( "was not active - removing it.\n" );
933 : }
934 0 : remove_name_from_namelist( subrec, namerec );
935 0 : namerec = NULL;
936 0 : wins_process_name_registration_request( subrec, p );
937 0 : return;
938 : }
939 :
940 : /*
941 : * Check that the group bits for the refreshing name and the
942 : * name in our database match. If not, refuse the refresh.
943 : * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
944 : */
945 0 : if( (namerec != NULL) &&
946 0 : ( (group && !NAME_GROUP(namerec))
947 0 : || (!group && NAME_GROUP(namerec)) ) ) {
948 0 : if( DEBUGLVL( 3 ) ) {
949 0 : dbgtext( "wins_process_name_refresh_request: " );
950 0 : dbgtext( "Name %s ", nmb_namestr(question) );
951 0 : dbgtext( "group bit = %s does not match ",
952 : group ? "True" : "False" );
953 0 : dbgtext( "group bit in WINS for this name.\n" );
954 : }
955 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
956 0 : return;
957 : }
958 :
959 : /*
960 : * For a unique name check that the person refreshing the name is
961 : * one of the registered IP addresses. If not - fail the refresh.
962 : * Do the same for group names with a type of 0x1c.
963 : * Just return success for unique 0x1d refreshes. For normal group
964 : * names update the ttl and return success.
965 : */
966 0 : if( (!group || (group && (question->name_type == 0x1c)))
967 0 : && find_ip_in_name_record(namerec, from_ip) ) {
968 : /*
969 : * Update the ttl.
970 : */
971 0 : update_name_ttl(namerec, ttl);
972 :
973 : /*
974 : * if the record is a replica:
975 : * we take ownership and update the version ID.
976 : */
977 0 : if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
978 0 : update_wins_owner(namerec, our_fake_ip);
979 0 : get_global_id_and_update(&namerec->data.id, True);
980 : }
981 :
982 0 : send_wins_name_registration_response(0, ttl, p);
983 0 : wins_hook("refresh", namerec, ttl);
984 0 : return;
985 0 : } else if((group && (question->name_type == 0x1c))) {
986 : /*
987 : * Added by crh for bug #1079.
988 : * Fix from Bert Driehuis
989 : */
990 0 : if( DEBUGLVL( 3 ) ) {
991 0 : dbgtext( "wins_process_name_refresh_request: " );
992 0 : dbgtext( "Name refresh for name %s, ",
993 : nmb_namestr(question) );
994 0 : dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
995 0 : dbgtext( "is not yet associated with " );
996 0 : dbgtext( "that name. Treating as registration.\n" );
997 : }
998 0 : wins_process_name_registration_request(subrec,p);
999 0 : return;
1000 0 : } else if(group) {
1001 : /*
1002 : * Normal groups are all registered with an IP address of
1003 : * 255.255.255.255 so we can't search for the IP address.
1004 : */
1005 0 : update_name_ttl(namerec, ttl);
1006 0 : wins_hook("refresh", namerec, ttl);
1007 0 : send_wins_name_registration_response(0, ttl, p);
1008 0 : return;
1009 0 : } else if(!group && (question->name_type == 0x1d)) {
1010 : /*
1011 : * Special name type - just pretend the refresh succeeded.
1012 : */
1013 0 : send_wins_name_registration_response(0, ttl, p);
1014 0 : return;
1015 : } else {
1016 : /*
1017 : * Fail the refresh.
1018 : */
1019 0 : if( DEBUGLVL( 3 ) ) {
1020 0 : dbgtext( "wins_process_name_refresh_request: " );
1021 0 : dbgtext( "Name refresh for name %s with IP %s ",
1022 : nmb_namestr(question), inet_ntoa(from_ip) );
1023 0 : dbgtext( "and is IP is not known to the name.\n" );
1024 : }
1025 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1026 0 : return;
1027 : }
1028 : }
1029 :
1030 : /***********************************************************************
1031 : Deal with a name registration request query success to a client that
1032 : owned the name.
1033 :
1034 : We have a locked pointer to the original packet stashed away in the
1035 : userdata pointer. The success here is actually a failure as it means
1036 : the client we queried wants to keep the name, so we must return
1037 : a registration failure to the original requester.
1038 : ************************************************************************/
1039 :
1040 0 : static void wins_register_query_success(struct subnet_record *subrec,
1041 : struct userdata_struct *userdata,
1042 : struct nmb_name *question_name,
1043 : struct in_addr ip,
1044 : struct res_rec *answers)
1045 : {
1046 : struct packet_struct *orig_reg_packet;
1047 :
1048 0 : memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1049 :
1050 0 : DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1051 : name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1052 :
1053 0 : send_wins_name_registration_response(ACT_ERR, 0, orig_reg_packet);
1054 :
1055 0 : orig_reg_packet->locked = False;
1056 0 : free_packet(orig_reg_packet);
1057 0 : }
1058 :
1059 : /***********************************************************************
1060 : Deal with a name registration request query failure to a client that
1061 : owned the name.
1062 :
1063 : We have a locked pointer to the original packet stashed away in the
1064 : userdata pointer. The failure here is actually a success as it means
1065 : the client we queried didn't want to keep the name, so we can remove
1066 : the old name record and then successfully add the new name.
1067 : ************************************************************************/
1068 :
1069 0 : static void wins_register_query_fail(struct subnet_record *subrec,
1070 : struct response_record *rrec,
1071 : struct nmb_name *question_name,
1072 : int rcode)
1073 : {
1074 0 : struct userdata_struct *userdata = rrec->userdata;
1075 : struct packet_struct *orig_reg_packet;
1076 0 : struct name_record *namerec = NULL;
1077 :
1078 0 : memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1079 :
1080 : /*
1081 : * We want to just add the name, as we now know the original owner
1082 : * didn't want it. But we can't just do that as an arbitrary
1083 : * amount of time may have taken place between the name query
1084 : * request and this timeout/error response. So we check that
1085 : * the name still exists and is in the same state - if so
1086 : * we remove it and call wins_process_name_registration_request()
1087 : * as we know it will do the right thing now.
1088 : */
1089 :
1090 0 : namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1091 :
1092 0 : if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1093 0 : ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1094 0 : remove_name_from_namelist( subrec, namerec);
1095 0 : namerec = NULL;
1096 : }
1097 :
1098 0 : if(namerec == NULL) {
1099 0 : wins_process_name_registration_request(subrec, orig_reg_packet);
1100 : } else {
1101 0 : DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1102 : "querying for name %s in order to replace it and this reply.\n",
1103 : nmb_namestr(question_name) ));
1104 : }
1105 :
1106 0 : orig_reg_packet->locked = False;
1107 0 : free_packet(orig_reg_packet);
1108 0 : }
1109 :
1110 : /***********************************************************************
1111 : Deal with a name registration request to a WINS server.
1112 :
1113 : Use the following pseudocode :
1114 :
1115 : registering_group
1116 : |
1117 : |
1118 : +--------name exists
1119 : | |
1120 : | |
1121 : | +--- existing name is group
1122 : | | |
1123 : | | |
1124 : | | +--- add name (return).
1125 : | |
1126 : | |
1127 : | +--- exiting name is unique
1128 : | |
1129 : | |
1130 : | +--- query existing owner (return).
1131 : |
1132 : |
1133 : +--------name doesn't exist
1134 : |
1135 : |
1136 : +--- add name (return).
1137 :
1138 : registering_unique
1139 : |
1140 : |
1141 : +--------name exists
1142 : | |
1143 : | |
1144 : | +--- existing name is group
1145 : | | |
1146 : | | |
1147 : | | +--- fail add (return).
1148 : | |
1149 : | |
1150 : | +--- exiting name is unique
1151 : | |
1152 : | |
1153 : | +--- query existing owner (return).
1154 : |
1155 : |
1156 : +--------name doesn't exist
1157 : |
1158 : |
1159 : +--- add name (return).
1160 :
1161 : As can be seen from the above, the two cases may be collapsed onto each
1162 : other with the exception of the case where the name already exists and
1163 : is a group name. This case we handle with an if statement.
1164 :
1165 : ************************************************************************/
1166 :
1167 0 : void wins_process_name_registration_request(struct subnet_record *subrec,
1168 : struct packet_struct *p)
1169 : {
1170 : unstring name;
1171 0 : struct nmb_packet *nmb = &p->packet.nmb;
1172 0 : struct nmb_name *question = &nmb->question.question_name;
1173 0 : bool bcast = nmb->header.nm_flags.bcast;
1174 0 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
1175 0 : int ttl = get_ttl_from_packet(nmb);
1176 0 : struct name_record *namerec = NULL;
1177 : struct in_addr from_ip;
1178 0 : bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1179 : struct in_addr our_fake_ip;
1180 :
1181 0 : our_fake_ip = interpret_addr2("0.0.0.0");
1182 0 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
1183 :
1184 0 : if(bcast) {
1185 : /*
1186 : * We should only get unicast name registration packets here.
1187 : * Anyone trying to register broadcast should not be going to a WINS
1188 : * server. Log an error here.
1189 : */
1190 :
1191 0 : DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1192 : received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1193 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1194 0 : return;
1195 : }
1196 :
1197 0 : DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1198 : IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1199 :
1200 : /*
1201 : * See if the name already exists.
1202 : */
1203 :
1204 0 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1205 :
1206 : /*
1207 : * if the record exists but NOT in active state,
1208 : * consider it dead.
1209 : */
1210 0 : if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1211 0 : DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1212 : not active - removing it.\n", nmb_namestr(question) ));
1213 0 : remove_name_from_namelist( subrec, namerec );
1214 0 : namerec = NULL;
1215 : }
1216 :
1217 : /*
1218 : * Deal with the case where the name found was a dns entry.
1219 : * Remove it as we now have a NetBIOS client registering the
1220 : * name.
1221 : */
1222 :
1223 0 : if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1224 0 : DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1225 : a dns lookup - removing it.\n", nmb_namestr(question) ));
1226 0 : remove_name_from_namelist( subrec, namerec );
1227 0 : namerec = NULL;
1228 : }
1229 :
1230 : /*
1231 : * Reject if the name exists and is not a REGISTER_NAME.
1232 : * (ie. Don't allow any static names to be overwritten.
1233 : */
1234 :
1235 0 : if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1236 0 : DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1237 : to register name %s. Name already exists in WINS with source type %d.\n",
1238 : nmb_namestr(question), namerec->data.source ));
1239 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1240 0 : return;
1241 : }
1242 :
1243 : /*
1244 : * Special policy decisions based on MS documentation.
1245 : * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1246 : * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1247 : */
1248 :
1249 : /*
1250 : * A group name is always added as the local broadcast address, except
1251 : * for group names ending in 0x1c.
1252 : * Group names with type 0x1c are registered with individual IP addresses.
1253 : */
1254 :
1255 0 : if(registering_group_name && (question->name_type != 0x1c)) {
1256 0 : from_ip = interpret_addr2("255.255.255.255");
1257 : }
1258 :
1259 : /*
1260 : * Ignore all attempts to register a unique 0x1d name, although return success.
1261 : */
1262 :
1263 0 : if(!registering_group_name && (question->name_type == 0x1d)) {
1264 0 : DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1265 : to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1266 0 : send_wins_name_registration_response(0, ttl, p);
1267 0 : return;
1268 : }
1269 :
1270 : /*
1271 : * Next two cases are the 'if statement' mentioned above.
1272 : */
1273 :
1274 0 : if((namerec != NULL) && NAME_GROUP(namerec)) {
1275 0 : if(registering_group_name) {
1276 : /*
1277 : * If we are adding a group name, the name exists and is also a group entry just add this
1278 : * IP address to it and update the ttl.
1279 : */
1280 :
1281 0 : DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1282 : inet_ntoa(from_ip), nmb_namestr(question) ));
1283 :
1284 : /*
1285 : * Check the ip address is not already in the group.
1286 : */
1287 :
1288 0 : if(!find_ip_in_name_record(namerec, from_ip)) {
1289 : /*
1290 : * Need to emulate the behaviour of Windows, as
1291 : * described in:
1292 : * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1293 : * (is there an MS reference for this
1294 : * somewhere?) because if the 1c list gets over
1295 : * 86 entries, the reply packet is too big
1296 : * (rdata>576 bytes) so no reply is sent.
1297 : *
1298 : * Keep only the "latest" 25 records, while
1299 : * ensuring that the PDC (0x1b) is never removed
1300 : * We do this by removing the first entry that
1301 : * isn't the 1b entry for the same name,
1302 : * on the grounds that insertion is at the end
1303 : * of the list, so the oldest entries are at
1304 : * the start.
1305 : *
1306 : */
1307 0 : while(namerec->data.num_ips>=25) {
1308 0 : struct name_record *name1brec = NULL;
1309 :
1310 : /* We only do this for 1c types. */
1311 0 : if (namerec->name.name_type != 0x1c) {
1312 0 : break;
1313 : }
1314 0 : DEBUG(3,("wins_process_name_registration_request: "
1315 : "More than 25 IPs already in "
1316 : "the list. Looking for a 1b "
1317 : "record\n"));
1318 :
1319 : /* Ensure we have all the active 1b
1320 : * names on the list. */
1321 0 : wins_delete_all_1b_in_memory_records();
1322 0 : fetch_all_active_wins_1b_names();
1323 :
1324 : /* Per the above, find the 1b record,
1325 : and then remove the first IP that isn't the same */
1326 0 : for(name1brec = subrec->namelist;
1327 0 : name1brec;
1328 0 : name1brec = name1brec->next ) {
1329 0 : if( WINS_STATE_ACTIVE(name1brec) &&
1330 0 : name1brec->name.name_type == 0x1b) {
1331 0 : DEBUG(3,("wins_process_name_registration_request: "
1332 : "Found the #1b record "
1333 : "with ip %s\n",
1334 : inet_ntoa(name1brec->data.ip[0])));
1335 0 : break;
1336 : }
1337 : }
1338 0 : if(!name1brec) {
1339 0 : DEBUG(3,("wins_process_name_registration_request: "
1340 : "Didn't find a #1b name record. "
1341 : "Removing the first available "
1342 : "entry %s\n",
1343 : inet_ntoa(namerec->data.ip[0])));
1344 0 : remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1345 0 : wins_hook("delete", namerec, 0);
1346 : } else {
1347 : int i;
1348 0 : for(i=0; i<namerec->data.num_ips; i++) {
1349 : /* The name1brec should only have
1350 : * the single IP address in it,
1351 : * so we only check against the first one*/
1352 0 : if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1353 : /* The i'th entry isn't the 1b address; delete it */
1354 0 : DEBUG(3,("wins_process_name_registration_request: "
1355 : "Entry at %d is not the #1b address. "
1356 : "About to remove it\n",
1357 : i));
1358 0 : remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1359 0 : wins_hook("delete", namerec, 0);
1360 0 : break;
1361 : }
1362 : }
1363 : }
1364 : }
1365 : /* The list is guaranteed to be < 25 entries now
1366 : * - safe to add a new one */
1367 0 : add_ip_to_name_record(namerec, from_ip);
1368 : /* we need to update the record for replication */
1369 0 : get_global_id_and_update(&namerec->data.id, True);
1370 :
1371 : /*
1372 : * if the record is a replica, we must change
1373 : * the wins owner to us to make the replication updates
1374 : * it on the other wins servers.
1375 : * And when the partner will receive this record,
1376 : * it will update its own record.
1377 : */
1378 :
1379 0 : update_wins_owner(namerec, our_fake_ip);
1380 : }
1381 0 : update_name_ttl(namerec, ttl);
1382 0 : wins_hook("refresh", namerec, ttl);
1383 0 : send_wins_name_registration_response(0, ttl, p);
1384 0 : return;
1385 : } else {
1386 :
1387 : /*
1388 : * If we are adding a unique name, the name exists in the WINS db
1389 : * and is a group name then reject the registration.
1390 : *
1391 : * explanation: groups have a higher priority than unique names.
1392 : */
1393 :
1394 0 : DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1395 : already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1396 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1397 0 : return;
1398 : }
1399 : }
1400 :
1401 : /*
1402 : * From here on down we know that if the name exists in the WINS db it is
1403 : * a unique name, not a group name.
1404 : */
1405 :
1406 : /*
1407 : * If the name exists and is one of our names then check the
1408 : * registering IP address. If it's not one of ours then automatically
1409 : * reject without doing the query - we know we will reject it.
1410 : */
1411 :
1412 0 : if ( namerec != NULL ) {
1413 0 : pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1414 0 : if( is_myname(name) ) {
1415 0 : if(!ismyip_v4(from_ip)) {
1416 0 : DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1417 : is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1418 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1419 0 : return;
1420 : } else {
1421 : /*
1422 : * It's one of our names and one of our IP's - update the ttl.
1423 : */
1424 0 : update_name_ttl(namerec, ttl);
1425 0 : wins_hook("refresh", namerec, ttl);
1426 0 : send_wins_name_registration_response(0, ttl, p);
1427 0 : return;
1428 : }
1429 : }
1430 : } else {
1431 0 : name[0] = '\0';
1432 : }
1433 :
1434 : /*
1435 : * If the name exists and it is a unique registration and the registering IP
1436 : * is the same as the (single) already registered IP then just update the ttl.
1437 : *
1438 : * But not if the record is an active replica. IF it's a replica, it means it can be
1439 : * the same client which has moved and not yet expired. So we don't update
1440 : * the ttl in this case and go beyond to do a WACK and query the old client
1441 : */
1442 :
1443 0 : if( !registering_group_name
1444 0 : && (namerec != NULL)
1445 0 : && (namerec->data.num_ips == 1)
1446 0 : && ip_equal_v4( namerec->data.ip[0], from_ip )
1447 0 : && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1448 0 : update_name_ttl( namerec, ttl );
1449 0 : wins_hook("refresh", namerec, ttl);
1450 0 : send_wins_name_registration_response( 0, ttl, p );
1451 0 : return;
1452 : }
1453 :
1454 : /*
1455 : * Finally if the name exists do a query to the registering machine
1456 : * to see if they still claim to have the name.
1457 : */
1458 :
1459 0 : if( namerec != NULL ) {
1460 : long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1461 0 : struct userdata_struct *userdata = (struct userdata_struct *)ud;
1462 :
1463 : /*
1464 : * First send a WACK to the registering machine.
1465 : */
1466 :
1467 0 : send_wins_wack_response(60, p);
1468 :
1469 : /*
1470 : * When the reply comes back we need the original packet.
1471 : * Lock this so it won't be freed and then put it into
1472 : * the userdata structure.
1473 : */
1474 :
1475 0 : p->locked = True;
1476 :
1477 0 : userdata = (struct userdata_struct *)ud;
1478 :
1479 0 : userdata->copy_fn = NULL;
1480 0 : userdata->free_fn = NULL;
1481 0 : userdata->userdata_len = sizeof(struct packet_struct *);
1482 0 : memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1483 :
1484 : /*
1485 : * Use the new call to send a query directly to an IP address.
1486 : * This sends the query directly to the IP address, and ensures
1487 : * the recursion desired flag is not set (you were right Luke :-).
1488 : * This function should *only* be called from the WINS server
1489 : * code. JRA.
1490 : */
1491 :
1492 0 : pull_ascii_nstring(name, sizeof(name), question->name);
1493 0 : query_name_from_wins_server( *namerec->data.ip,
1494 : name,
1495 0 : question->name_type,
1496 : wins_register_query_success,
1497 : wins_register_query_fail,
1498 : userdata );
1499 0 : return;
1500 : }
1501 :
1502 : /*
1503 : * Name did not exist - add it.
1504 : */
1505 :
1506 0 : pull_ascii_nstring(name, sizeof(name), question->name);
1507 0 : add_name_to_subnet( subrec, name, question->name_type,
1508 : nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1509 :
1510 0 : if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1511 0 : get_global_id_and_update(&namerec->data.id, True);
1512 0 : update_wins_owner(namerec, our_fake_ip);
1513 0 : update_wins_flag(namerec, WINS_ACTIVE);
1514 0 : wins_hook("add", namerec, ttl);
1515 : }
1516 :
1517 0 : send_wins_name_registration_response(0, ttl, p);
1518 : }
1519 :
1520 : /***********************************************************************
1521 : Deal with a mutihomed name query success to the machine that
1522 : requested the multihomed name registration.
1523 :
1524 : We have a locked pointer to the original packet stashed away in the
1525 : userdata pointer.
1526 : ************************************************************************/
1527 :
1528 0 : static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1529 : struct userdata_struct *userdata,
1530 : struct nmb_name *question_name,
1531 : struct in_addr ip,
1532 : struct res_rec *answers)
1533 : {
1534 : struct packet_struct *orig_reg_packet;
1535 : struct nmb_packet *nmb;
1536 0 : struct name_record *namerec = NULL;
1537 : struct in_addr from_ip;
1538 : int ttl;
1539 : struct in_addr our_fake_ip;
1540 :
1541 0 : our_fake_ip = interpret_addr2("0.0.0.0");
1542 0 : memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1543 :
1544 0 : nmb = &orig_reg_packet->packet.nmb;
1545 :
1546 0 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
1547 0 : ttl = get_ttl_from_packet(nmb);
1548 :
1549 : /*
1550 : * We want to just add the new IP, as we now know the requesting
1551 : * machine claims to own it. But we can't just do that as an arbitrary
1552 : * amount of time may have taken place between the name query
1553 : * request and this response. So we check that
1554 : * the name still exists and is in the same state - if so
1555 : * we just add the extra IP and update the ttl.
1556 : */
1557 :
1558 0 : namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1559 :
1560 0 : if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1561 0 : DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1562 : a subsequent IP address.\n", nmb_namestr(question_name) ));
1563 0 : send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1564 :
1565 0 : orig_reg_packet->locked = False;
1566 0 : free_packet(orig_reg_packet);
1567 :
1568 0 : return;
1569 : }
1570 :
1571 0 : if(!find_ip_in_name_record(namerec, from_ip)) {
1572 0 : add_ip_to_name_record(namerec, from_ip);
1573 : }
1574 :
1575 0 : get_global_id_and_update(&namerec->data.id, True);
1576 0 : update_wins_owner(namerec, our_fake_ip);
1577 0 : update_wins_flag(namerec, WINS_ACTIVE);
1578 0 : update_name_ttl(namerec, ttl);
1579 0 : wins_hook("add", namerec, ttl);
1580 0 : send_wins_name_registration_response(0, ttl, orig_reg_packet);
1581 :
1582 0 : orig_reg_packet->locked = False;
1583 0 : free_packet(orig_reg_packet);
1584 : }
1585 :
1586 : /***********************************************************************
1587 : Deal with a name registration request query failure to a client that
1588 : owned the name.
1589 :
1590 : We have a locked pointer to the original packet stashed away in the
1591 : userdata pointer.
1592 : ************************************************************************/
1593 :
1594 0 : static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1595 : struct response_record *rrec,
1596 : struct nmb_name *question_name,
1597 : int rcode)
1598 : {
1599 0 : struct userdata_struct *userdata = rrec->userdata;
1600 : struct packet_struct *orig_reg_packet;
1601 :
1602 0 : memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1603 :
1604 0 : DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1605 : query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1606 0 : send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1607 :
1608 0 : orig_reg_packet->locked = False;
1609 0 : free_packet(orig_reg_packet);
1610 0 : return;
1611 : }
1612 :
1613 : /***********************************************************************
1614 : Deal with a multihomed name registration request to a WINS server.
1615 : These cannot be group name registrations.
1616 : ***********************************************************************/
1617 :
1618 0 : void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1619 : struct packet_struct *p)
1620 : {
1621 0 : struct nmb_packet *nmb = &p->packet.nmb;
1622 0 : struct nmb_name *question = &nmb->question.question_name;
1623 0 : bool bcast = nmb->header.nm_flags.bcast;
1624 0 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
1625 0 : int ttl = get_ttl_from_packet(nmb);
1626 0 : struct name_record *namerec = NULL;
1627 : struct in_addr from_ip;
1628 0 : bool group = (nb_flags & NB_GROUP) ? True : False;
1629 : struct in_addr our_fake_ip;
1630 : unstring qname;
1631 :
1632 0 : our_fake_ip = interpret_addr2("0.0.0.0");
1633 0 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
1634 :
1635 0 : if(bcast) {
1636 : /*
1637 : * We should only get unicast name registration packets here.
1638 : * Anyone trying to register broadcast should not be going to a WINS
1639 : * server. Log an error here.
1640 : */
1641 :
1642 0 : DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1643 : received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1644 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1645 0 : return;
1646 : }
1647 :
1648 : /*
1649 : * Only unique names should be registered multihomed.
1650 : */
1651 :
1652 0 : if(group) {
1653 0 : DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1654 : received for name %s from IP %s on subnet %s. Error - group names should not be multihomed.\n",
1655 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1656 0 : return;
1657 : }
1658 :
1659 0 : DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1660 : IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1661 :
1662 : /*
1663 : * Deal with policy regarding 0x1d names.
1664 : */
1665 :
1666 0 : if(question->name_type == 0x1d) {
1667 0 : DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1668 : to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1669 0 : send_wins_name_registration_response(0, ttl, p);
1670 0 : return;
1671 : }
1672 :
1673 : /*
1674 : * See if the name already exists.
1675 : */
1676 :
1677 0 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1678 :
1679 : /*
1680 : * if the record exists but NOT in active state,
1681 : * consider it dead.
1682 : */
1683 :
1684 0 : if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1685 0 : DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1686 0 : remove_name_from_namelist(subrec, namerec);
1687 0 : namerec = NULL;
1688 : }
1689 :
1690 : /*
1691 : * Deal with the case where the name found was a dns entry.
1692 : * Remove it as we now have a NetBIOS client registering the
1693 : * name.
1694 : */
1695 :
1696 0 : if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1697 0 : DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1698 : - removing it.\n", nmb_namestr(question) ));
1699 0 : remove_name_from_namelist( subrec, namerec);
1700 0 : namerec = NULL;
1701 : }
1702 :
1703 : /*
1704 : * Reject if the name exists and is not a REGISTER_NAME.
1705 : * (ie. Don't allow any static names to be overwritten.
1706 : */
1707 :
1708 0 : if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1709 0 : DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1710 : to register name %s. Name already exists in WINS with source type %d.\n",
1711 : nmb_namestr(question), namerec->data.source ));
1712 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1713 0 : return;
1714 : }
1715 :
1716 : /*
1717 : * Reject if the name exists and is a GROUP name and is active.
1718 : */
1719 :
1720 0 : if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1721 0 : DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1722 : already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1723 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1724 0 : return;
1725 : }
1726 :
1727 : /*
1728 : * From here on down we know that if the name exists in the WINS db it is
1729 : * a unique name, not a group name.
1730 : */
1731 :
1732 : /*
1733 : * If the name exists and is one of our names then check the
1734 : * registering IP address. If it's not one of ours then automatically
1735 : * reject without doing the query - we know we will reject it.
1736 : */
1737 :
1738 0 : if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1739 0 : if(!ismyip_v4(from_ip)) {
1740 0 : DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1741 : is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1742 0 : send_wins_name_registration_response(RFS_ERR, 0, p);
1743 0 : return;
1744 : } else {
1745 : /*
1746 : * It's one of our names and one of our IP's. Ensure the IP is in the record and
1747 : * update the ttl. Update the version ID to force replication.
1748 : */
1749 0 : update_name_ttl(namerec, ttl);
1750 :
1751 0 : if(!find_ip_in_name_record(namerec, from_ip)) {
1752 0 : get_global_id_and_update(&namerec->data.id, True);
1753 0 : update_wins_owner(namerec, our_fake_ip);
1754 0 : update_wins_flag(namerec, WINS_ACTIVE);
1755 :
1756 0 : add_ip_to_name_record(namerec, from_ip);
1757 : }
1758 :
1759 0 : wins_hook("refresh", namerec, ttl);
1760 0 : send_wins_name_registration_response(0, ttl, p);
1761 0 : return;
1762 : }
1763 : }
1764 :
1765 : /*
1766 : * If the name exists and is active, check if the IP address is already registered
1767 : * to that name. If so then update the ttl and reply success.
1768 : */
1769 :
1770 0 : if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1771 0 : update_name_ttl(namerec, ttl);
1772 :
1773 : /*
1774 : * If it's a replica, we need to become the wins owner
1775 : * to force the replication
1776 : */
1777 0 : if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1778 0 : get_global_id_and_update(&namerec->data.id, True);
1779 0 : update_wins_owner(namerec, our_fake_ip);
1780 0 : update_wins_flag(namerec, WINS_ACTIVE);
1781 : }
1782 :
1783 0 : wins_hook("refresh", namerec, ttl);
1784 0 : send_wins_name_registration_response(0, ttl, p);
1785 0 : return;
1786 : }
1787 :
1788 : /*
1789 : * If the name exists do a query to the owner
1790 : * to see if they still want the name.
1791 : */
1792 :
1793 0 : if(namerec != NULL) {
1794 : long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1795 0 : struct userdata_struct *userdata = (struct userdata_struct *)ud;
1796 :
1797 : /*
1798 : * First send a WACK to the registering machine.
1799 : */
1800 :
1801 0 : send_wins_wack_response(60, p);
1802 :
1803 : /*
1804 : * When the reply comes back we need the original packet.
1805 : * Lock this so it won't be freed and then put it into
1806 : * the userdata structure.
1807 : */
1808 :
1809 0 : p->locked = True;
1810 :
1811 0 : userdata = (struct userdata_struct *)ud;
1812 :
1813 0 : userdata->copy_fn = NULL;
1814 0 : userdata->free_fn = NULL;
1815 0 : userdata->userdata_len = sizeof(struct packet_struct *);
1816 0 : memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1817 :
1818 : /*
1819 : * Use the new call to send a query directly to an IP address.
1820 : * This sends the query directly to the IP address, and ensures
1821 : * the recursion desired flag is not set (you were right Luke :-).
1822 : * This function should *only* be called from the WINS server
1823 : * code. JRA.
1824 : *
1825 : * Note that this packet is sent to the current owner of the name,
1826 : * not the person who sent the packet
1827 : */
1828 :
1829 0 : pull_ascii_nstring( qname, sizeof(qname), question->name);
1830 0 : query_name_from_wins_server( namerec->data.ip[0],
1831 : qname,
1832 0 : question->name_type,
1833 : wins_multihomed_register_query_success,
1834 : wins_multihomed_register_query_fail,
1835 : userdata );
1836 :
1837 0 : return;
1838 : }
1839 :
1840 : /*
1841 : * Name did not exist - add it.
1842 : */
1843 :
1844 0 : pull_ascii_nstring( qname, sizeof(qname), question->name);
1845 0 : add_name_to_subnet( subrec, qname, question->name_type,
1846 : nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1847 :
1848 0 : if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1849 0 : get_global_id_and_update(&namerec->data.id, True);
1850 0 : update_wins_owner(namerec, our_fake_ip);
1851 0 : update_wins_flag(namerec, WINS_ACTIVE);
1852 0 : wins_hook("add", namerec, ttl);
1853 : }
1854 :
1855 0 : send_wins_name_registration_response(0, ttl, p);
1856 : }
1857 :
1858 : /***********************************************************************
1859 : Fetch all *<1b> names from the WINS db and store on the namelist.
1860 : ***********************************************************************/
1861 :
1862 0 : static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1863 : {
1864 0 : struct name_record *namerec = NULL;
1865 :
1866 0 : if (kbuf.dsize != sizeof(unstring) + 1) {
1867 0 : return 0;
1868 : }
1869 :
1870 : /* Filter out all non-1b names. */
1871 0 : if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1872 0 : return 0;
1873 : }
1874 :
1875 0 : namerec = wins_record_to_name_record(kbuf, dbuf);
1876 0 : if (!namerec) {
1877 0 : return 0;
1878 : }
1879 :
1880 0 : DLIST_ADD(wins_server_subnet->namelist, namerec);
1881 0 : return 0;
1882 : }
1883 :
1884 0 : void fetch_all_active_wins_1b_names(void)
1885 : {
1886 0 : tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1887 0 : }
1888 :
1889 : /***********************************************************************
1890 : Deal with the special name query for *<1b>.
1891 : ***********************************************************************/
1892 :
1893 0 : static void process_wins_dmb_query_request(struct subnet_record *subrec,
1894 : struct packet_struct *p)
1895 : {
1896 0 : struct name_record *namerec = NULL;
1897 : char *prdata;
1898 : int num_ips;
1899 :
1900 : /*
1901 : * Go through all the ACTIVE names in the WINS db looking for those
1902 : * ending in <1b>. Use this to calculate the number of IP
1903 : * addresses we need to return.
1904 : */
1905 :
1906 0 : num_ips = 0;
1907 :
1908 : /* First, clear the in memory list - we're going to re-populate
1909 : it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1910 :
1911 0 : wins_delete_all_tmp_in_memory_records();
1912 :
1913 0 : fetch_all_active_wins_1b_names();
1914 :
1915 0 : for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1916 0 : if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1917 0 : num_ips += namerec->data.num_ips;
1918 : }
1919 : }
1920 :
1921 0 : if(num_ips == 0) {
1922 : /*
1923 : * There are no 0x1b names registered. Return name query fail.
1924 : */
1925 0 : send_wins_name_query_response(NAM_ERR, p, NULL);
1926 0 : return;
1927 : }
1928 :
1929 0 : if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1930 0 : DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1931 0 : return;
1932 : }
1933 :
1934 : /*
1935 : * Go through all the names again in the WINS db looking for those
1936 : * ending in <1b>. Add their IP addresses into the list we will
1937 : * return.
1938 : */
1939 :
1940 0 : num_ips = 0;
1941 0 : for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1942 0 : if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1943 : int i;
1944 0 : for(i = 0; i < namerec->data.num_ips; i++) {
1945 0 : set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1946 0 : putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1947 0 : num_ips++;
1948 : }
1949 : }
1950 : }
1951 :
1952 : /*
1953 : * Send back the reply containing the IP list.
1954 : */
1955 :
1956 0 : reply_netbios_packet(p, /* Packet to reply to. */
1957 : 0, /* Result code. */
1958 : WINS_QUERY, /* nmbd type code. */
1959 : NMB_NAME_QUERY_OPCODE, /* opcode. */
1960 : lp_min_wins_ttl(), /* ttl. */
1961 : prdata, /* data to send. */
1962 : num_ips*6); /* data length. */
1963 :
1964 0 : SAFE_FREE(prdata);
1965 : }
1966 :
1967 : /****************************************************************************
1968 : Send a WINS name query response.
1969 : **************************************************************************/
1970 :
1971 0 : void send_wins_name_query_response(int rcode, struct packet_struct *p,
1972 : struct name_record *namerec)
1973 : {
1974 : char rdata[6];
1975 0 : char *prdata = rdata;
1976 0 : int reply_data_len = 0;
1977 0 : int ttl = 0;
1978 : int i;
1979 :
1980 0 : memset(rdata,'\0',6);
1981 :
1982 0 : if(rcode == 0) {
1983 :
1984 : int ip_count;
1985 :
1986 0 : ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1987 :
1988 : /* The netbios reply packet data section is limited to 576 bytes. In theory
1989 : * this should give us space for 96 addresses, but in practice, 86 appears
1990 : * to be the max (don't know why). If we send any more than that,
1991 : * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1992 : * overflow. Keep the count to 85 and it will be ok */
1993 0 : ip_count=namerec->data.num_ips;
1994 0 : if(ip_count>85) {
1995 0 : ip_count=85;
1996 : }
1997 :
1998 : /* Copy all known ip addresses into the return data. */
1999 : /* Optimise for the common case of one IP address so we don't need a malloc. */
2000 :
2001 0 : if( ip_count == 1 ) {
2002 0 : prdata = rdata;
2003 : } else {
2004 0 : if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
2005 0 : DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
2006 0 : return;
2007 : }
2008 : }
2009 :
2010 0 : for(i = 0; i < ip_count; i++) {
2011 0 : set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
2012 0 : putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
2013 : }
2014 :
2015 0 : sort_query_replies(prdata, i, p->ip);
2016 0 : reply_data_len = ip_count * 6;
2017 : }
2018 :
2019 0 : reply_netbios_packet(p, /* Packet to reply to. */
2020 : rcode, /* Result code. */
2021 : WINS_QUERY, /* nmbd type code. */
2022 : NMB_NAME_QUERY_OPCODE, /* opcode. */
2023 : ttl, /* ttl. */
2024 : prdata, /* data to send. */
2025 : reply_data_len); /* data length. */
2026 :
2027 0 : if(prdata != rdata) {
2028 0 : SAFE_FREE(prdata);
2029 : }
2030 : }
2031 :
2032 : /***********************************************************************
2033 : Deal with a name query.
2034 : ***********************************************************************/
2035 :
2036 0 : void wins_process_name_query_request(struct subnet_record *subrec,
2037 : struct packet_struct *p)
2038 : {
2039 0 : struct nmb_packet *nmb = &p->packet.nmb;
2040 0 : struct nmb_name *question = &nmb->question.question_name;
2041 0 : struct name_record *namerec = NULL;
2042 : unstring qname;
2043 :
2044 0 : DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2045 : nmb_namestr(question), inet_ntoa(p->ip) ));
2046 :
2047 : /*
2048 : * Special name code. If the queried name is *<1b> then search
2049 : * the entire WINS database and return a list of all the IP addresses
2050 : * registered to any <1b> name. This is to allow domain master browsers
2051 : * to discover other domains that may not have a presence on their subnet.
2052 : */
2053 :
2054 0 : pull_ascii_nstring(qname, sizeof(qname), question->name);
2055 0 : if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2056 0 : process_wins_dmb_query_request( subrec, p);
2057 0 : return;
2058 : }
2059 :
2060 0 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2061 :
2062 0 : if(namerec != NULL) {
2063 : /*
2064 : * If the name is not anymore in active state then reply not found.
2065 : * it's fair even if we keep it in the cache for days.
2066 : */
2067 0 : if (!WINS_STATE_ACTIVE(namerec)) {
2068 0 : DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2069 : nmb_namestr(question) ));
2070 0 : send_wins_name_query_response(NAM_ERR, p, namerec);
2071 0 : return;
2072 : }
2073 :
2074 : /*
2075 : * If it's a DNSFAIL_NAME then reply name not found.
2076 : */
2077 :
2078 0 : if( namerec->data.source == DNSFAIL_NAME ) {
2079 0 : DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2080 : nmb_namestr(question) ));
2081 0 : send_wins_name_query_response(NAM_ERR, p, namerec);
2082 0 : return;
2083 : }
2084 :
2085 : /*
2086 : * If the name has expired then reply name not found.
2087 : */
2088 :
2089 0 : if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2090 0 : DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2091 : nmb_namestr(question) ));
2092 0 : send_wins_name_query_response(NAM_ERR, p, namerec);
2093 0 : return;
2094 : }
2095 :
2096 0 : DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2097 : nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2098 :
2099 0 : send_wins_name_query_response(0, p, namerec);
2100 0 : return;
2101 : }
2102 :
2103 : /*
2104 : * Name not found in WINS - try a dns query if it's a 0x20 name.
2105 : */
2106 :
2107 0 : if(lp_wins_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2108 0 : DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2109 : nmb_namestr(question) ));
2110 :
2111 0 : queue_dns_query(p, question);
2112 0 : return;
2113 : }
2114 :
2115 : /*
2116 : * Name not found - return error.
2117 : */
2118 :
2119 0 : send_wins_name_query_response(NAM_ERR, p, NULL);
2120 : }
2121 :
2122 : /****************************************************************************
2123 : Send a WINS name release response.
2124 : **************************************************************************/
2125 :
2126 0 : static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2127 : {
2128 0 : struct nmb_packet *nmb = &p->packet.nmb;
2129 : char rdata[6];
2130 :
2131 0 : memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2132 :
2133 0 : reply_netbios_packet(p, /* Packet to reply to. */
2134 : rcode, /* Result code. */
2135 : NMB_REL, /* nmbd type code. */
2136 : NMB_NAME_RELEASE_OPCODE, /* opcode. */
2137 : 0, /* ttl. */
2138 : rdata, /* data to send. */
2139 : 6); /* data length. */
2140 0 : }
2141 :
2142 : /***********************************************************************
2143 : Deal with a name release.
2144 : ***********************************************************************/
2145 :
2146 0 : void wins_process_name_release_request(struct subnet_record *subrec,
2147 : struct packet_struct *p)
2148 : {
2149 0 : struct nmb_packet *nmb = &p->packet.nmb;
2150 0 : struct nmb_name *question = &nmb->question.question_name;
2151 0 : bool bcast = nmb->header.nm_flags.bcast;
2152 0 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
2153 0 : struct name_record *namerec = NULL;
2154 : struct in_addr from_ip;
2155 0 : bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;
2156 :
2157 0 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
2158 :
2159 0 : if(bcast) {
2160 : /*
2161 : * We should only get unicast name registration packets here.
2162 : * Anyone trying to register broadcast should not be going to a WINS
2163 : * server. Log an error here.
2164 : */
2165 :
2166 0 : DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2167 : received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2168 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2169 0 : return;
2170 : }
2171 :
2172 0 : DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2173 : IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2174 :
2175 : /*
2176 : * Deal with policy regarding 0x1d names.
2177 : */
2178 :
2179 0 : if(!releasing_group_name && (question->name_type == 0x1d)) {
2180 0 : DEBUG(3,("wins_process_name_release_request: Ignoring request \
2181 : to release name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
2182 0 : send_wins_name_release_response(0, p);
2183 0 : return;
2184 : }
2185 :
2186 : /*
2187 : * See if the name already exists.
2188 : */
2189 :
2190 0 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2191 :
2192 0 : if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2193 0 : send_wins_name_release_response(NAM_ERR, p);
2194 0 : return;
2195 : }
2196 :
2197 : /*
2198 : * Check that the sending machine has permission to release this name.
2199 : * If it's a group name not ending in 0x1c then just say yes and let
2200 : * the group time out.
2201 : */
2202 :
2203 0 : if(releasing_group_name && (question->name_type != 0x1c)) {
2204 0 : send_wins_name_release_response(0, p);
2205 0 : return;
2206 : }
2207 :
2208 : /*
2209 : * Check that the releasing node is on the list of IP addresses
2210 : * for this name. Disallow the release if not.
2211 : */
2212 :
2213 0 : if(!find_ip_in_name_record(namerec, from_ip)) {
2214 0 : DEBUG(3,("wins_process_name_release_request: Refusing request to \
2215 : release name %s as IP %s is not one of the known IP's for this name.\n",
2216 : nmb_namestr(question), inet_ntoa(from_ip) ));
2217 0 : send_wins_name_release_response(NAM_ERR, p);
2218 0 : return;
2219 : }
2220 :
2221 : /*
2222 : * Check if the record is active. IF it's already released
2223 : * or tombstoned, refuse the release.
2224 : */
2225 :
2226 0 : if (!WINS_STATE_ACTIVE(namerec)) {
2227 0 : DEBUG(3,("wins_process_name_release_request: Refusing request to \
2228 : release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2229 0 : send_wins_name_release_response(NAM_ERR, p);
2230 0 : return;
2231 : }
2232 :
2233 : /*
2234 : * Check if the record is a 0x1c group
2235 : * and has more then one ip
2236 : * remove only this address.
2237 : */
2238 :
2239 0 : if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2240 0 : remove_ip_from_name_record(namerec, from_ip);
2241 0 : DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2242 : inet_ntoa(from_ip),nmb_namestr(question)));
2243 0 : wins_hook("delete", namerec, 0);
2244 0 : send_wins_name_release_response(0, p);
2245 0 : return;
2246 : }
2247 :
2248 : /*
2249 : * Send a release response.
2250 : * Flag the name as released and update the ttl
2251 : */
2252 :
2253 0 : namerec->data.wins_flags |= WINS_RELEASED;
2254 0 : update_name_ttl(namerec, EXTINCTION_INTERVAL);
2255 :
2256 0 : wins_hook("delete", namerec, 0);
2257 0 : send_wins_name_release_response(0, p);
2258 : }
2259 :
2260 : /*******************************************************************
2261 : WINS time dependent processing.
2262 : ******************************************************************/
2263 :
2264 0 : static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2265 : {
2266 0 : time_t t = *(time_t *)state;
2267 0 : bool store_record = False;
2268 0 : struct name_record *namerec = NULL;
2269 : struct in_addr our_fake_ip;
2270 :
2271 0 : our_fake_ip = interpret_addr2("0.0.0.0");
2272 0 : if (kbuf.dsize != sizeof(unstring) + 1) {
2273 0 : return 0;
2274 : }
2275 :
2276 0 : namerec = wins_record_to_name_record(kbuf, dbuf);
2277 0 : if (!namerec) {
2278 0 : return 0;
2279 : }
2280 :
2281 0 : if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2282 0 : if( namerec->data.source == SELF_NAME ) {
2283 0 : DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2284 : wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2285 0 : namerec->data.death_time += 300;
2286 0 : store_record = True;
2287 0 : goto done;
2288 0 : } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2289 0 : DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2290 : nmb_namestr(&namerec->name)));
2291 0 : remove_name_from_wins_namelist(namerec );
2292 0 : goto done;
2293 : }
2294 :
2295 : /* handle records, samba is the wins owner */
2296 0 : if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2297 0 : switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2298 0 : case WINS_ACTIVE:
2299 0 : namerec->data.wins_flags&=~WINS_STATE_MASK;
2300 0 : namerec->data.wins_flags|=WINS_RELEASED;
2301 0 : namerec->data.death_time = t + EXTINCTION_INTERVAL;
2302 0 : DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2303 : nmb_namestr(&namerec->name)));
2304 0 : store_record = True;
2305 0 : goto done;
2306 0 : case WINS_RELEASED:
2307 0 : namerec->data.wins_flags&=~WINS_STATE_MASK;
2308 0 : namerec->data.wins_flags|=WINS_TOMBSTONED;
2309 0 : namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2310 0 : get_global_id_and_update(&namerec->data.id, True);
2311 0 : DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2312 : nmb_namestr(&namerec->name)));
2313 0 : store_record = True;
2314 0 : goto done;
2315 0 : case WINS_TOMBSTONED:
2316 0 : DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2317 : nmb_namestr(&namerec->name)));
2318 0 : remove_name_from_wins_namelist(namerec );
2319 0 : goto done;
2320 : }
2321 : } else {
2322 0 : switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2323 0 : case WINS_ACTIVE:
2324 : /* that's not as MS says it should be */
2325 0 : namerec->data.wins_flags&=~WINS_STATE_MASK;
2326 0 : namerec->data.wins_flags|=WINS_TOMBSTONED;
2327 0 : namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2328 0 : DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2329 : nmb_namestr(&namerec->name)));
2330 0 : store_record = True;
2331 0 : goto done;
2332 0 : case WINS_TOMBSTONED:
2333 0 : DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2334 : nmb_namestr(&namerec->name)));
2335 0 : remove_name_from_wins_namelist(namerec );
2336 0 : goto done;
2337 0 : case WINS_RELEASED:
2338 0 : DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2339 : we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2340 0 : goto done;
2341 : }
2342 : }
2343 : }
2344 :
2345 0 : done:
2346 :
2347 0 : if (store_record) {
2348 0 : wins_store_changed_namerec(namerec);
2349 : }
2350 :
2351 0 : SAFE_FREE(namerec->data.ip);
2352 0 : SAFE_FREE(namerec);
2353 :
2354 0 : return 0;
2355 : }
2356 :
2357 : /*******************************************************************
2358 : Time dependent wins processing.
2359 : ******************************************************************/
2360 :
2361 15165 : void initiate_wins_processing(time_t t)
2362 : {
2363 : static time_t lasttime = 0;
2364 :
2365 15165 : if (!lasttime) {
2366 39 : lasttime = t;
2367 : }
2368 15165 : if (t - lasttime < 20) {
2369 13760 : return;
2370 : }
2371 :
2372 1405 : if(!lp_we_are_a_wins_server()) {
2373 1405 : lasttime = t;
2374 1405 : return;
2375 : }
2376 :
2377 0 : tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2378 :
2379 0 : wins_delete_all_tmp_in_memory_records();
2380 :
2381 0 : wins_write_database(t, True);
2382 :
2383 0 : lasttime = t;
2384 : }
2385 :
2386 : /*******************************************************************
2387 : Write out one record.
2388 : ******************************************************************/
2389 :
2390 0 : void wins_write_name_record(struct name_record *namerec, FILE *fp)
2391 : {
2392 : int i;
2393 : struct tm *tm;
2394 :
2395 0 : DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2396 :
2397 0 : if( namerec->data.death_time != PERMANENT_TTL ) {
2398 : char *ts, *nl;
2399 :
2400 0 : tm = localtime(&namerec->data.death_time);
2401 0 : if (!tm) {
2402 0 : return;
2403 : }
2404 0 : ts = asctime(tm);
2405 0 : if (!ts) {
2406 0 : return;
2407 : }
2408 0 : nl = strrchr( ts, '\n' );
2409 0 : if( NULL != nl ) {
2410 0 : *nl = '\0';
2411 : }
2412 0 : DEBUGADD(4,("TTL = %s ", ts ));
2413 : } else {
2414 0 : DEBUGADD(4,("TTL = PERMANENT "));
2415 : }
2416 :
2417 0 : for (i = 0; i < namerec->data.num_ips; i++) {
2418 0 : DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2419 : }
2420 0 : DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2421 :
2422 0 : if( namerec->data.source == REGISTER_NAME ) {
2423 : unstring name;
2424 0 : pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2425 0 : fprintf(fp, "\"%s#%02x\" %d ", name,
2426 : namerec->name.name_type, /* Ignore scope. */
2427 0 : (int)namerec->data.death_time);
2428 :
2429 0 : for (i = 0; i < namerec->data.num_ips; i++)
2430 0 : fprintf(fp, "%s ", inet_ntoa(namerec->data.ip[i]));
2431 0 : fprintf(fp, "%2xR\n", namerec->data.nb_flags);
2432 : }
2433 : }
2434 :
2435 : /*******************************************************************
2436 : Write out the current WINS database.
2437 : ******************************************************************/
2438 :
2439 0 : static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2440 : {
2441 0 : struct name_record *namerec = NULL;
2442 0 : FILE *fp = (FILE *)state;
2443 :
2444 0 : if (kbuf.dsize != sizeof(unstring) + 1) {
2445 0 : return 0;
2446 : }
2447 :
2448 0 : namerec = wins_record_to_name_record(kbuf, dbuf);
2449 0 : if (!namerec) {
2450 0 : return 0;
2451 : }
2452 :
2453 0 : wins_write_name_record(namerec, fp);
2454 :
2455 0 : SAFE_FREE(namerec->data.ip);
2456 0 : SAFE_FREE(namerec);
2457 0 : return 0;
2458 : }
2459 :
2460 :
2461 39 : void wins_write_database(time_t t, bool background)
2462 : {
2463 : static time_t last_write_time = 0;
2464 39 : char *fname = NULL;
2465 39 : char *fnamenew = NULL;
2466 :
2467 : int fd;
2468 : FILE *fp;
2469 :
2470 39 : if (background) {
2471 0 : if (!last_write_time) {
2472 0 : last_write_time = t;
2473 : }
2474 0 : if (t - last_write_time < 120) {
2475 39 : return;
2476 : }
2477 :
2478 : }
2479 :
2480 39 : if(!lp_we_are_a_wins_server()) {
2481 39 : return;
2482 : }
2483 :
2484 : /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2485 0 : if (background) {
2486 0 : CatchChild();
2487 0 : if (fork()) {
2488 0 : return;
2489 : }
2490 0 : if (tdb_reopen(wins_tdb)) {
2491 0 : DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2492 : strerror(errno)));
2493 0 : _exit(0);
2494 : return;
2495 : }
2496 : }
2497 :
2498 0 : if (!(fname = state_path(talloc_tos(), WINS_LIST))) {
2499 0 : goto err_exit;
2500 : }
2501 : /* This is safe as the 0 length means "don't expand". */
2502 0 : all_string_sub(fname,"//", "/", 0);
2503 :
2504 0 : if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)getpid()) < 0) {
2505 0 : goto err_exit;
2506 : }
2507 :
2508 0 : fd = open(fnamenew, O_WRONLY|O_CREAT, 0644);
2509 0 : if (fd == -1) {
2510 0 : DBG_ERR("Can't open %s: %s\n", fnamenew, strerror(errno));
2511 0 : goto err_exit;
2512 : }
2513 :
2514 0 : fp = fdopen(fd, "w");
2515 0 : if (fp == NULL) {
2516 0 : DBG_ERR("fdopen failed: %s\n", strerror(errno));
2517 0 : close(fd);
2518 0 : goto err_exit;
2519 : }
2520 0 : fd = -1;
2521 :
2522 0 : DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2523 :
2524 0 : fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2525 :
2526 0 : tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2527 :
2528 0 : fclose(fp);
2529 0 : chmod(fnamenew,0644);
2530 0 : unlink(fname);
2531 0 : rename(fnamenew,fname);
2532 :
2533 0 : err_exit:
2534 :
2535 0 : SAFE_FREE(fnamenew);
2536 0 : TALLOC_FREE(fname);
2537 :
2538 0 : if (background) {
2539 0 : _exit(0);
2540 : }
2541 : }
2542 :
2543 : #if 0
2544 : Until winsrepl is done.
2545 : /****************************************************************************
2546 : Process a internal Samba message receiving a wins record.
2547 : ***************************************************************************/
2548 :
2549 : void nmbd_wins_new_entry(struct messaging_context *msg,
2550 : void *private_data,
2551 : uint32_t msg_type,
2552 : struct server_id server_id,
2553 : DATA_BLOB *data)
2554 : {
2555 : WINS_RECORD *record;
2556 : struct name_record *namerec = NULL;
2557 : struct name_record *new_namerec = NULL;
2558 : struct nmb_name question;
2559 : bool overwrite=False;
2560 : struct in_addr our_fake_ip;
2561 : int i;
2562 :
2563 : our_fake_ip = interpret_addr2("0.0.0.0");
2564 : if (buf==NULL) {
2565 : return;
2566 : }
2567 :
2568 : /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2569 : record=(WINS_RECORD *)buf;
2570 :
2571 : make_nmb_name(&question, record->name, record->type);
2572 :
2573 : namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2574 :
2575 : /* record doesn't exist, add it */
2576 : if (namerec == NULL) {
2577 : DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2578 : record->name, record->type, inet_ntoa(record->wins_ip)));
2579 :
2580 : new_namerec=add_name_to_subnet( wins_server_subnet,
2581 : record->name,
2582 : record->type,
2583 : record->nb_flags,
2584 : EXTINCTION_INTERVAL,
2585 : REGISTER_NAME,
2586 : record->num_ips,
2587 : record->ip);
2588 :
2589 : if (new_namerec!=NULL) {
2590 : update_wins_owner(new_namerec, record->wins_ip);
2591 : update_wins_flag(new_namerec, record->wins_flags);
2592 : new_namerec->data.id=record->id;
2593 :
2594 : wins_server_subnet->namelist_changed = True;
2595 : }
2596 : }
2597 :
2598 : /* check if we have a conflict */
2599 : if (namerec != NULL) {
2600 : /* both records are UNIQUE */
2601 : if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2602 :
2603 : /* the database record is a replica */
2604 : if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2605 : if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2606 : if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2607 : overwrite=True;
2608 : } else
2609 : overwrite=True;
2610 : } else {
2611 : /* we are the wins owner of the database record */
2612 : /* the 2 records have the same IP address */
2613 : if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2614 : if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2615 : get_global_id_and_update(&namerec->data.id, True);
2616 : else
2617 : overwrite=True;
2618 :
2619 : } else {
2620 : /* the 2 records have different IP address */
2621 : if (namerec->data.wins_flags&WINS_ACTIVE) {
2622 : if (record->wins_flags&WINS_TOMBSTONED)
2623 : get_global_id_and_update(&namerec->data.id, True);
2624 : if (record->wins_flags&WINS_ACTIVE)
2625 : /* send conflict challenge to the replica node */
2626 : ;
2627 : } else
2628 : overwrite=True;
2629 : }
2630 :
2631 : }
2632 : }
2633 :
2634 : /* the replica is a standard group */
2635 : if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2636 : /* if the database record is unique and active force a name release */
2637 : if (namerec->data.wins_flags&WINS_UNIQUE)
2638 : /* send a release name to the unique node */
2639 : ;
2640 : overwrite=True;
2641 :
2642 : }
2643 :
2644 : /* the replica is a special group */
2645 : if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2646 : if (namerec->data.wins_flags&WINS_ACTIVE) {
2647 : for (i=0; i<record->num_ips; i++)
2648 : if(!find_ip_in_name_record(namerec, record->ip[i]))
2649 : add_ip_to_name_record(namerec, record->ip[i]);
2650 : } else {
2651 : overwrite=True;
2652 : }
2653 : }
2654 :
2655 : /* the replica is a multihomed host */
2656 :
2657 : /* I'm giving up on multi homed. Too much complex to understand */
2658 :
2659 : if (record->wins_flags&WINS_MHOMED) {
2660 : if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2661 : if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2662 : overwrite=True;
2663 : }
2664 : else {
2665 : if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2666 : overwrite=True;
2667 :
2668 : if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2669 : if (namerec->data.wins_flags&WINS_UNIQUE)
2670 : get_global_id_and_update(&namerec->data.id, True);
2671 :
2672 : }
2673 :
2674 : if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2675 : if (namerec->data.wins_flags&WINS_UNIQUE ||
2676 : namerec->data.wins_flags&WINS_MHOMED)
2677 : if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2678 : overwrite=True;
2679 :
2680 : }
2681 :
2682 : if (overwrite == False)
2683 : DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2684 : record->name, record->type, inet_ntoa(record->wins_ip)));
2685 : else {
2686 : DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2687 : record->name, record->type, inet_ntoa(record->wins_ip)));
2688 :
2689 : /* remove the old record and add a new one */
2690 : remove_name_from_namelist( wins_server_subnet, namerec );
2691 : new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2692 : EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2693 : if (new_namerec!=NULL) {
2694 : update_wins_owner(new_namerec, record->wins_ip);
2695 : update_wins_flag(new_namerec, record->wins_flags);
2696 : new_namerec->data.id=record->id;
2697 :
2698 : wins_server_subnet->namelist_changed = True;
2699 : }
2700 :
2701 : wins_server_subnet->namelist_changed = True;
2702 : }
2703 :
2704 : }
2705 : }
2706 : #endif
|