we never pass any userdata when doing name registrations on the
[kai/samba-autobuild/.git] / source3 / nmbd / nmbd_nameregister.c
1 /* 
2    Unix SMB/CIFS implementation.
3    NBT netbios routines and daemon - version 2
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
6    Copyright (C) Jeremy Allison 1994-1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    
22 */
23
24 #include "includes.h"
25
26 extern fstring global_myworkgroup;
27
28 /****************************************************************************
29  Deal with a response packet when registering one of our names.
30 ****************************************************************************/
31
32 static void register_name_response(struct subnet_record *subrec,
33                        struct response_record *rrec, struct packet_struct *p)
34 {
35   /* 
36    * If we are registering broadcast, then getting a response is an
37    * error - we do not have the name. If we are registering unicast,
38    * then we expect to get a response.
39    */
40
41   struct nmb_packet *nmb = &p->packet.nmb;
42   BOOL bcast = nmb->header.nm_flags.bcast;
43   BOOL success = True;
44   struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
45   struct nmb_name *answer_name = &nmb->answers->rr_name;
46   int ttl = 0;
47   uint16 nb_flags = 0;
48   struct in_addr registered_ip;
49
50   /* Sanity check. Ensure that the answer name in the incoming packet is the
51      same as the requested name in the outgoing packet. */
52
53   if(!question_name || !answer_name)
54   {
55     DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
56            question_name ? "question_name" : "answer_name" ));
57     return;
58   }
59
60   if(!nmb_name_equal(question_name, answer_name))
61   {
62     DEBUG(0,("register_name_response: Answer name %s differs from question \
63 name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
64     return;
65   }
66
67   if(bcast)
68   {
69     /*
70      * Special hack to cope with old Samba nmbd's.
71      * Earlier versions of Samba (up to 1.9.16p11) respond 
72      * to a broadcast name registration of WORKGROUP<1b> when 
73      * they should not. Hence, until these versions are gone, 
74      * we should treat such errors as success for this particular
75      * case only. jallison@whistle.com.
76      */
77
78 #if 1 /* OLD_SAMBA_SERVER_HACK */
79     if((nmb->header.rcode == ACT_ERR) && strequal(global_myworkgroup, answer_name->name) &&
80          (answer_name->name_type == 0x1b))
81     {
82       /* Pretend we did not get this. */
83       rrec->num_msgs--;
84
85       DEBUG(5,("register_name_response: Ignoring broadcast response to \
86 registration of name %s due to old Samba server bug.\n", nmb_namestr(answer_name)));
87       return;
88     }
89 #endif /* OLD_SAMBA_SERVER_HACK */
90
91     /* Someone else has the name. Log the problem. */
92     DEBUG(1,("register_name_response: Failed to register \
93 name %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n", 
94               nmb_namestr(answer_name), 
95               subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
96     success = False;
97   }
98   else
99   {
100     /* Unicast - check to see if the response allows us to have the name. */
101     if(nmb->header.rcode != 0)
102     {
103       /* Error code - we didn't get the name. */
104       success = False;
105
106       DEBUG(0,("register_name_response: server at IP %s rejected our \
107 name registration of %s with error code %d.\n", inet_ntoa(p->ip), 
108                   nmb_namestr(answer_name), nmb->header.rcode));
109
110     }
111     else if(nmb->header.opcode == NMB_WACK_OPCODE)
112     {
113       /* WINS server is telling us to wait. Pretend we didn't get
114          the response but don't send out any more register requests. */
115
116       DEBUG(5,("register_name_response: WACK from WINS server %s in registering \
117 name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
118
119       rrec->repeat_count = 0;
120       /* How long we should wait for. */
121       rrec->repeat_time = p->timestamp + nmb->answers->ttl;
122       rrec->num_msgs--;
123       return;
124     }
125     else
126     {
127       success = True;
128       /* Get the data we need to pass to the success function. */
129       nb_flags = get_nb_flags(nmb->answers->rdata);
130       putip((char*)&registered_ip,&nmb->answers->rdata[2]);
131       ttl = nmb->answers->ttl;
132     }
133   } 
134
135   DEBUG(5,("register_name_response: %s in registering name %s on subnet %s.\n",
136         success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
137
138   if(success)
139   {
140     /* Enter the registered name into the subnet name database before calling
141        the success function. */
142     standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
143     if( rrec->success_fn)
144       (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
145   }
146   else
147   {
148     if( rrec->fail_fn)
149       (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
150     /* Remove the name. */
151     standard_fail_register( subrec, rrec, question_name);
152   }
153
154   /* Ensure we don't retry. */
155   remove_response_record(subrec, rrec);
156 }
157
158 /****************************************************************************
159  Deal with a timeout when registering one of our names.
160 ****************************************************************************/
161
162 static void register_name_timeout_response(struct subnet_record *subrec,
163                        struct response_record *rrec)
164 {
165   /*
166    * If we are registering unicast, then NOT getting a response is an
167    * error - we do not have the name. If we are registering broadcast,
168    * then we don't expect to get a response.
169    */
170
171   struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
172   BOOL bcast = sent_nmb->header.nm_flags.bcast;
173   BOOL success = False;
174   struct nmb_name *question_name = &sent_nmb->question.question_name;
175   uint16 nb_flags = 0;
176   int ttl = 0;
177   struct in_addr registered_ip;
178
179   if(bcast)
180   {
181     if(rrec->num_msgs == 0)
182     {
183       /* Not receiving a message is success for broadcast registration. */
184       success = True; 
185
186       /* Pull the success values from the original request packet. */
187       nb_flags = get_nb_flags(sent_nmb->additional->rdata);
188       ttl = sent_nmb->additional->ttl;
189       putip(&registered_ip,&sent_nmb->additional->rdata[2]);
190     }
191   }
192   else
193   {
194     /* Unicast - if no responses then it's an error. */
195     if(rrec->num_msgs == 0)
196     {
197       DEBUG(2,("register_name_timeout_response: WINS server at address %s is not \
198 responding.\n", inet_ntoa(rrec->packet->ip)));
199
200       /* mark it temporarily dead */
201       wins_srv_died(rrec->packet->ip);
202
203       /* and try the next wins server in our failover list */
204       rrec->packet->ip = wins_srv_ip();
205
206       /* also update the UNICODE subnet IPs */
207       subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
208
209       /* Keep trying to contact the WINS server periodically. This allows
210          us to work correctly if the WINS server is down temporarily when
211          we come up. */
212
213       /* Reset the number of attempts to zero and double the interval between
214          retries. Max out at 5 minutes. */
215       rrec->repeat_count = 3;
216       rrec->repeat_interval *= 2;
217       if(rrec->repeat_interval > (5 * 60))
218         rrec->repeat_interval = (5 * 60);
219       rrec->repeat_time = time(NULL) + rrec->repeat_interval;
220       rrec->in_expiration_processing = False;
221
222       DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
223               (int)rrec->repeat_interval));
224       return; /* Don't remove the response record. */
225     }
226   }
227
228   DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
229         success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
230   if(success)
231   {
232     /* Enter the registered name into the subnet name database before calling
233        the success function. */
234     standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
235     if( rrec->success_fn)
236       (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
237   }
238   else
239   {
240     if( rrec->fail_fn)
241       (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
242     /* Remove the name. */
243     standard_fail_register( subrec, rrec, question_name);
244   }
245
246   /* Ensure we don't retry. */
247   remove_response_record(subrec, rrec);
248 }
249
250 /****************************************************************************
251  Try and register one of our names on the unicast subnet - multihomed.
252 ****************************************************************************/
253
254 static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
255                                       register_name_success_function success_fn,
256                                       register_name_fail_function fail_fn)
257 {
258   /*
259      If we are adding a group name, we just send multiple
260      register name packets to the WINS server (this is an
261      internet group name.
262
263      If we are adding a unique name, We need first to add 
264      our names to the unicast subnet namelist. This is 
265      because when a WINS server receives a multihomed 
266      registration request, the first thing it does is to 
267      send a name query to the registering machine, to see 
268      if it has put the name in it's local namelist.
269      We need the name there so the query response code in
270      nmbd_incomingrequests.c will find it.
271
272      We are adding this name prematurely (we don't really
273      have it yet), but as this is on the unicast subnet
274      only we will get away with this (only the WINS server
275      will ever query names from us on this subnet).
276    */
277
278         int num_ips=0;
279         int i;
280         struct in_addr *ip_list = NULL;
281         struct subnet_record *subrec;
282         
283         for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
284                 num_ips++;
285         
286         if((ip_list = (struct in_addr *)malloc(num_ips * sizeof(struct in_addr)))==NULL) {
287                 DEBUG(0,("multihomed_register_name: malloc fail !\n"));
288                 return True;
289         }
290
291         for( subrec = FIRST_SUBNET, i = 0; 
292              subrec;
293              subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) {
294                 ip_list[i] = subrec->myip;
295         }
296
297         (void)add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
298                                   nb_flags, lp_max_ttl(), SELF_NAME,
299                                   num_ips, ip_list);
300
301         /* Now try and register the name, num_ips times. On the last time use
302            the given success and fail functions. */
303         
304         for (i = 0; i < num_ips; i++) {
305                 if (queue_register_multihomed_name( unicast_subnet,
306                                                     register_name_response,
307                                                     register_name_timeout_response,
308                                                     (i == num_ips - 1) ? success_fn : NULL,
309                                                     (i == num_ips - 1) ? fail_fn : NULL,
310                                                     NULL,
311                                                     nmbname,
312                                                     nb_flags,
313                                                     ip_list[i]) == NULL) {
314                         DEBUG(0,("multihomed_register_name: Failed to send packet trying to \
315 register name %s IP %s\n", nmb_namestr(nmbname), inet_ntoa(ip_list[i]) ));
316                         
317                         SAFE_FREE(ip_list);
318                         return True;
319                 }
320         }
321         
322         SAFE_FREE(ip_list);
323         
324         return False;
325 }
326
327 /****************************************************************************
328  Try and register one of our names.
329 ****************************************************************************/
330
331 BOOL register_name(struct subnet_record *subrec,
332                    char *name, int type, uint16 nb_flags,
333                    register_name_success_function success_fn,
334                    register_name_fail_function fail_fn,
335                    struct userdata_struct *userdata)
336 {
337   struct nmb_name nmbname;
338
339   make_nmb_name(&nmbname, name, type);
340
341   /* Always set the NB_ACTIVE flag on the name we are
342      registering. Doesn't make sense without it.
343    */
344
345   nb_flags |= NB_ACTIVE;
346
347   /* If this is the unicast subnet, and we are a multi-homed
348      host, then register a multi-homed name. */
349
350   if( (subrec == unicast_subnet) && we_are_multihomed()) {
351           return multihomed_register_name(&nmbname, nb_flags,
352                                           success_fn, fail_fn);
353   }
354
355   if(queue_register_name( subrec,
356         register_name_response,
357         register_name_timeout_response,
358         success_fn,
359         fail_fn,
360         userdata,
361         &nmbname,
362         nb_flags) == NULL)
363   {
364     DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
365           nmb_namestr(&nmbname)));
366     return True;
367   }
368   return False;
369 }
370
371 /****************************************************************************
372  Try and refresh one of our names.
373 ****************************************************************************/
374
375 BOOL refresh_name(struct subnet_record *subrec, struct name_record *namerec,
376                   refresh_name_success_function success_fn,
377                   refresh_name_fail_function fail_fn,
378                   struct userdata_struct *userdata)
379 {
380   int i;
381
382   /* 
383    * Go through and refresh the name for all known ip addresses.
384    * Only call the success/fail function on the last one (it should
385    * only be done once).
386    */
387
388   for( i = 0; i < namerec->data.num_ips; i++)
389   {
390     if(queue_refresh_name( subrec,
391         register_name_response,
392         register_name_timeout_response,
393         (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
394         (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
395         (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
396         namerec,
397         namerec->data.ip[i]) == NULL)
398     {
399       DEBUG(0,("refresh_name: Failed to send packet trying to refresh name %s\n",
400             nmb_namestr(&namerec->name)));
401       return True;
402     }
403   }
404   return False;
405 }