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