Convert all uses of uint8/16/32 to _t in nmbd and the include file.
[samba.git] / source3 / nmbd / nmbd_namequery.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-2003
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 3 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, see <http://www.gnu.org/licenses/>.
20    
21 */
22
23 #include "includes.h"
24 #include "nmbd/nmbd.h"
25
26 /****************************************************************************
27  Deal with a response packet when querying a name.
28 ****************************************************************************/
29
30 static void query_name_response( struct subnet_record   *subrec,
31                                  struct response_record *rrec,
32                                  struct packet_struct   *p)
33 {
34         struct nmb_packet *nmb = &p->packet.nmb;
35         bool success = False;
36         struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
37         struct in_addr answer_ip;
38
39         zero_ip_v4(&answer_ip);
40
41         /* Ensure we don't retry the query but leave the response record cleanup
42                 to the timeout code. We may get more answer responses in which case
43                 we should mark the name in conflict.. */
44         rrec->repeat_count = 0;
45
46         if(rrec->num_msgs == 1) {
47                 /* This is the first response. */
48
49                 if(nmb->header.opcode == NMB_WACK_OPCODE) {
50                         /* WINS server is telling us to wait. Pretend we didn't get
51                                 the response but don't send out any more query requests. */
52
53                         if( DEBUGLVL( 5 ) ) {
54                                 dbgtext( "query_name_response: " );
55                                 dbgtext( "WACK from WINS server %s ", inet_ntoa(p->ip) );
56                                 dbgtext( "in querying name %s ", nmb_namestr(question_name) );
57                                 dbgtext( "on subnet %s.\n", subrec->subnet_name );
58                         }
59   
60                         rrec->repeat_count = 0;
61                         /* How long we should wait for. */
62                         if (nmb->answers) {
63                                 rrec->repeat_time = p->timestamp + nmb->answers->ttl;
64                         } else {
65                                 /* No answer - this is probably a corrupt
66                                    packet.... */
67                                 DEBUG(0,("query_name_response: missing answer record in "
68                                         "NMB_WACK_OPCODE response.\n"));
69                                 rrec->repeat_time = p->timestamp + 10;
70                         }
71                         rrec->num_msgs--;
72                         return;
73                 } else if(nmb->header.rcode != 0) {
74
75                         success = False;
76
77                         if( DEBUGLVL( 5 ) ) {
78                                 dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
79                                 dbgtext( "- negative response from IP %s ", inet_ntoa(p->ip) );
80                                 dbgtext( "for name %s. ", nmb_namestr(question_name) );
81                                 dbgtext( "Error code was %d.\n", nmb->header.rcode );
82                         }
83                 } else {
84                         if (!nmb->answers) {
85                                 dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
86                                 dbgtext( "IP %s ", inet_ntoa(p->ip) );
87                                 dbgtext( "returned a success response with no answer\n" );
88                                 return;
89                         }
90
91                         success = True;
92
93                         putip((char *)&answer_ip,&nmb->answers->rdata[2]);
94         
95                         if( DEBUGLVL( 5 ) ) {
96                                 dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
97                                 dbgtext( "- positive response from IP %s ", inet_ntoa(p->ip) );
98                                 dbgtext( "for name %s.  ", nmb_namestr(question_name) );
99                                 dbgtext( "IP of that name is %s\n", inet_ntoa(answer_ip) );
100                         }
101
102                         /* Interestingly, we could add these names to our namelists, and
103                                 change nmbd to a model that checked its own name cache first,
104                                 before sending out a query. This is a task for another day, though.
105                         */
106                 }
107         } else if( rrec->num_msgs > 1) {
108
109                 if( DEBUGLVL( 0 ) ) {
110                         if (nmb->answers)
111                                 putip( (char *)&answer_ip, &nmb->answers->rdata[2] );
112                         dbgtext( "query_name_response: " );
113                         dbgtext( "Multiple (%d) responses ", rrec->num_msgs );
114                         dbgtext( "received for a query on subnet %s ", subrec->subnet_name );
115                         dbgtext( "for name %s.\nThis response ", nmb_namestr(question_name) );
116                         dbgtext( "was from IP %s, reporting ", inet_ntoa(p->ip) );
117                         dbgtext( "an IP address of %s.\n", inet_ntoa(answer_ip) );
118                 }
119
120                 /* We have already called the success or fail function, so we
121                         don't call again here. Leave the response record around in
122                         case we get more responses. */
123
124                 return; 
125         }
126   
127         if(success && rrec->success_fn)
128                 (*(query_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
129         else if( rrec->fail_fn)
130                 (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
131
132 }
133
134 /****************************************************************************
135  Deal with a timeout when querying a name.
136 ****************************************************************************/
137
138 static void query_name_timeout_response(struct subnet_record *subrec,
139                        struct response_record *rrec)
140 {
141         struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
142         /* We can only fail here, never succeed. */
143         bool failed = True;
144         struct nmb_name *question_name = &sent_nmb->question.question_name;
145
146         if(rrec->num_msgs != 0) {
147                 /* We got at least one response, and have called the success/fail
148                         function already. */
149
150                 failed = False; 
151         }
152
153         if(failed) {
154                 if( DEBUGLVL( 5 ) ) {
155                         dbgtext( "query_name_timeout_response: No response to " );
156                         dbgtext( "query for name %s ", nmb_namestr(question_name) );
157                         dbgtext( "on subnet %s.\n", subrec->subnet_name );
158                 }
159
160                 if(rrec->fail_fn)
161                         (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
162         }
163
164         remove_response_record(subrec, rrec);
165 }
166
167 /****************************************************************************
168  Lookup a name on our local namelists. We check the lmhosts file first. If the
169  name is not there we look for the name on the given subnet.
170 ****************************************************************************/
171
172 static bool query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
173                                   struct name_record **namerecp) 
174 {
175         struct name_record *namerec;
176
177         *namerecp = NULL;
178
179         if(find_name_in_lmhosts(nmbname, namerecp))
180                 return True;
181   
182         if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
183                 return False;
184
185         if( NAME_IS_ACTIVE(namerec) && ( (namerec->data.source == SELF_NAME) || (namerec->data.source == LMHOSTS_NAME) ) ) {
186                 *namerecp = namerec;
187                 return True;
188         } 
189         return False;
190 }
191
192 /****************************************************************************
193  Try and query for a name.
194 ****************************************************************************/
195
196 bool query_name(struct subnet_record *subrec, const char *name, int type,
197                    query_name_success_function success_fn,
198                    query_name_fail_function fail_fn, 
199                    struct userdata_struct *userdata)
200 {
201         struct nmb_name nmbname;
202         struct name_record *namerec;
203
204         make_nmb_name(&nmbname, name, type);
205
206         /*
207          * We need to check our local namelists first.
208          * It may be an magic name, lmhosts name or just
209          * a name we have registered.
210          */
211
212         if(query_local_namelists(subrec, &nmbname, &namerec) == True) {
213                 struct res_rec rrec;
214                 int i;
215
216                 memset((char *)&rrec, '\0', sizeof(struct res_rec));
217
218                 /* Fake up the needed res_rec just in case it's used. */
219                 rrec.rr_name = nmbname;
220                 rrec.rr_type = RR_TYPE_NB;
221                 rrec.rr_class = RR_CLASS_IN;
222                 rrec.ttl = PERMANENT_TTL;
223                 rrec.rdlength = namerec->data.num_ips * 6;
224                 if(rrec.rdlength > MAX_DGRAM_SIZE) {
225                         if( DEBUGLVL( 0 ) ) {
226                                 dbgtext( "query_name: nmbd internal error - " );
227                                 dbgtext( "there are %d ip addresses ", namerec->data.num_ips );
228                                 dbgtext( "for name %s.\n", nmb_namestr(&nmbname) );
229                         }
230                         return False;
231                 }
232
233                 for( i = 0; i < namerec->data.num_ips; i++) {
234                         set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
235                         putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
236                 }
237
238                 /* Call the success function directly. */
239                 if(success_fn)
240                         (*(query_name_success_function)success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
241                 return False;
242         }
243
244         if(queue_query_name( subrec, query_name_response, query_name_timeout_response, success_fn, fail_fn, userdata, &nmbname) == NULL) {
245                 if( DEBUGLVL( 0 ) ) {
246                         dbgtext( "query_name: Failed to send packet " );
247                         dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
248                 }
249                 return True;
250         }
251         return False;
252 }
253
254 /****************************************************************************
255  Try and query for a name from nmbd acting as a WINS server.
256 ****************************************************************************/
257
258 bool query_name_from_wins_server(struct in_addr ip_to, 
259                    const char *name, int type,
260                    query_name_success_function success_fn,
261                    query_name_fail_function fail_fn, 
262                    struct userdata_struct *userdata)
263 {
264         struct nmb_name nmbname;
265
266         make_nmb_name(&nmbname, name, type);
267
268         if(queue_query_name_from_wins_server( ip_to, query_name_response, query_name_timeout_response, success_fn, fail_fn, userdata, &nmbname) == NULL) {
269                 if( DEBUGLVL( 0 ) ) {
270                         dbgtext( "query_name_from_wins_server: Failed to send packet " );
271                         dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
272                 }
273                 return True;
274         }
275         return False;
276 }