Try to get the compiler not to complain about assignments and truth values...
[Samba/ekacnet.git] / source / nmbd / nmbd_incomingrequests.c
blob81e6bb9629f4e326670b5fab74c5cb350308e926
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7 Copyright (C) Jeremy Allison 1994-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This file contains all the code to process NetBIOS requests coming
24 in on port 137. It does not deal with the code needed to service
25 WINS server requests, but only broadcast and unicast requests.
29 #include "includes.h"
31 extern fstring global_myworkgroup;
33 /****************************************************************************
34 Send a name release response.
35 **************************************************************************/
37 static void send_name_release_response(int rcode, struct packet_struct *p)
39 struct nmb_packet *nmb = &p->packet.nmb;
40 char rdata[6];
42 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
44 reply_netbios_packet(p, /* Packet to reply to. */
45 rcode, /* Result code. */
46 NMB_REL, /* nmbd type code. */
47 NMB_NAME_RELEASE_OPCODE, /* opcode. */
48 0, /* ttl. */
49 rdata, /* data to send. */
50 6); /* data length. */
53 /****************************************************************************
54 Process a name release packet on a broadcast subnet.
55 Ignore it if it's not one of our names.
56 ****************************************************************************/
58 void process_name_release_request(struct subnet_record *subrec,
59 struct packet_struct *p)
61 struct nmb_packet *nmb = &p->packet.nmb;
62 struct in_addr owner_ip;
63 struct nmb_name *question = &nmb->question.question_name;
64 BOOL bcast = nmb->header.nm_flags.bcast;
65 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
66 BOOL group = (nb_flags & NB_GROUP) ? True : False;
67 struct name_record *namerec;
68 int rcode = 0;
70 putip((char *)&owner_ip,&nmb->additional->rdata[2]);
72 if(!bcast)
74 /* We should only get broadcast name release packets here.
75 Anyone trying to release unicast should be going to a WINS
76 server. If the code gets here, then either we are not a wins
77 server and they sent it anyway, or we are a WINS server and
78 the request was malformed. Either way, log an error here.
79 and send an error reply back.
81 DEBUG(0,("process_name_release_request: unicast name release request \
82 received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
83 nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
85 send_name_release_response(FMT_ERR, p);
86 return;
89 DEBUG(3,("process_name_release_request: Name release on name %s, \
90 subnet %s from owner IP %s\n",
91 nmb_namestr(&nmb->question.question_name),
92 subrec->subnet_name, inet_ntoa(owner_ip)));
94 /* If someone is releasing a broadcast group name, just ignore it. */
95 if( group && !ismyip(owner_ip) )
96 return;
99 * Code to work around a bug in FTP OnNet software NBT implementation.
100 * They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
101 * names and *don't set the group bit* !!!!!
104 if( !group && !ismyip(owner_ip) && strequal(question->name, global_myworkgroup) &&
105 ((question->name_type == 0x0) || (question->name_type == 0x1e)))
107 DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
108 group release name %s from IP %s on subnet %s with no group bit set.\n",
109 nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
110 return;
113 namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_ANY_NAME);
115 /* We only care about someone trying to release one of our names. */
116 if( namerec
117 && ( (namerec->data.source == SELF_NAME)
118 || (namerec->data.source == PERMANENT_NAME) ) )
120 rcode = ACT_ERR;
121 DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
122 on subnet %s being rejected as it is one of our names.\n",
123 nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
126 if(rcode == 0)
127 return;
129 /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
130 send_name_release_response(rcode, p);
133 /****************************************************************************
134 Send a name registration response.
135 **************************************************************************/
137 static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
139 struct nmb_packet *nmb = &p->packet.nmb;
140 char rdata[6];
142 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
144 reply_netbios_packet(p, /* Packet to reply to. */
145 rcode, /* Result code. */
146 NMB_REG, /* nmbd type code. */
147 NMB_NAME_REG_OPCODE, /* opcode. */
148 ttl, /* ttl. */
149 rdata, /* data to send. */
150 6); /* data length. */
153 /****************************************************************************
154 Process a name refresh request on a broadcast subnet.
155 **************************************************************************/
157 void process_name_refresh_request(struct subnet_record *subrec,
158 struct packet_struct *p)
161 struct nmb_packet *nmb = &p->packet.nmb;
162 struct nmb_name *question = &nmb->question.question_name;
163 BOOL bcast = nmb->header.nm_flags.bcast;
164 struct in_addr from_ip;
166 putip((char *)&from_ip,&nmb->additional->rdata[2]);
168 if(!bcast)
170 /* We should only get broadcast name refresh packets here.
171 Anyone trying to refresh unicast should be going to a WINS
172 server. If the code gets here, then either we are not a wins
173 server and they sent it anyway, or we are a WINS server and
174 the request was malformed. Either way, log an error here.
175 and send an error reply back.
177 DEBUG(0,("process_name_refresh_request: unicast name registration request \
178 received for name %s from IP %s on subnet %s.\n",
179 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
180 DEBUG(0,("Error - should be sent to WINS server\n"));
182 send_name_registration_response(FMT_ERR, 0, p);
183 return;
186 /* Just log a message. We really don't care about broadcast name
187 refreshes. */
189 DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
190 IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
194 /****************************************************************************
195 Process a name registration request on a broadcast subnet.
196 **************************************************************************/
198 void process_name_registration_request(struct subnet_record *subrec,
199 struct packet_struct *p)
201 struct nmb_packet *nmb = &p->packet.nmb;
202 struct nmb_name *question = &nmb->question.question_name;
203 BOOL bcast = nmb->header.nm_flags.bcast;
204 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
205 BOOL group = (nb_flags & NB_GROUP) ? True : False;
206 struct name_record *namerec = NULL;
207 int ttl = nmb->additional->ttl;
208 struct in_addr from_ip;
210 putip((char *)&from_ip,&nmb->additional->rdata[2]);
212 if(!bcast)
214 /* We should only get broadcast name registration packets here.
215 Anyone trying to register unicast should be going to a WINS
216 server. If the code gets here, then either we are not a wins
217 server and they sent it anyway, or we are a WINS server and
218 the request was malformed. Either way, log an error here.
219 and send an error reply back.
221 DEBUG(0,("process_name_registration_request: unicast name registration request \
222 received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
223 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
225 send_name_registration_response(FMT_ERR, 0, p);
226 return;
229 DEBUG(3,("process_name_registration_request: Name registration for name %s \
230 IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
232 /* See if the name already exists. */
233 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
236 * If the name being registered exists and is a WINS_PROXY_NAME
237 * then delete the WINS proxy name entry so we don't reply erroneously
238 * later to queries.
241 if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME))
243 remove_name_from_namelist( subrec, namerec );
244 namerec = NULL;
247 if (!group)
249 /* Unique name. */
251 if( (namerec != NULL)
252 && ( (namerec->data.source == SELF_NAME)
253 || (namerec->data.source == PERMANENT_NAME)
254 || NAME_GROUP(namerec) ) )
256 /* No-one can register one of Samba's names, nor can they
257 register a name that's a group name as a unique name */
259 send_name_registration_response(ACT_ERR, 0, p);
260 return;
262 else if(namerec != NULL)
264 /* Update the namelist record with the new information. */
265 namerec->data.ip[0] = from_ip;
266 update_name_ttl(namerec, ttl);
268 DEBUG(3,("process_name_registration_request: Updated name record %s \
269 with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
270 return;
273 else
275 /* Group name. */
277 if( (namerec != NULL)
278 && !NAME_GROUP(namerec)
279 && ( (namerec->data.source == SELF_NAME)
280 || (namerec->data.source == PERMANENT_NAME) ) )
282 /* Disallow group names when we have a unique name. */
283 send_name_registration_response(ACT_ERR, 0, p);
284 return;
289 /****************************************************************************
290 This is used to sort names for a name status into a sensible order.
291 We put our own names first, then in alphabetical order.
292 **************************************************************************/
294 static int status_compare(char *n1,char *n2)
296 extern pstring global_myname;
297 int l1,l2,l3;
299 /* It's a bit tricky because the names are space padded */
300 for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
301 for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
302 l3 = strlen(global_myname);
304 if ((l1==l3) && strncmp(n1,global_myname,l3) == 0 &&
305 (l2!=l3 || strncmp(n2,global_myname,l3) != 0))
306 return -1;
308 if ((l2==l3) && strncmp(n2,global_myname,l3) == 0 &&
309 (l1!=l3 || strncmp(n1,global_myname,l3) != 0))
310 return 1;
312 return memcmp(n1,n2,18);
316 /****************************************************************************
317 Process a node status query
318 ****************************************************************************/
320 void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
322 struct nmb_packet *nmb = &p->packet.nmb;
323 char *qname = nmb->question.question_name.name;
324 int ques_type = nmb->question.question_name.name_type;
325 char rdata[MAX_DGRAM_SIZE];
326 char *countptr, *buf, *bufend, *buf0;
327 int names_added,i;
328 struct name_record *namerec;
330 DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
331 subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip),
332 subrec->subnet_name));
334 if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name,
335 FIND_SELF_NAME)) == 0)
337 DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
338 subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
339 inet_ntoa(p->ip), subrec->subnet_name));
341 return;
344 /* this is not an exact calculation. the 46 is for the stats buffer
345 and the 60 is to leave room for the header etc */
346 bufend = &rdata[MAX_DGRAM_SIZE] - (18 + 46 + 60);
347 countptr = buf = rdata;
348 buf += 1;
349 buf0 = buf;
351 names_added = 0;
353 namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
355 while (buf < bufend)
357 if( (namerec->data.source == SELF_NAME)
358 || (namerec->data.source == PERMANENT_NAME) )
360 int name_type = namerec->name.name_type;
362 if (!strequal(namerec->name.name,"*") &&
363 !strequal(namerec->name.name,"__SAMBA__") &&
364 (name_type < 0x1b || name_type >= 0x20 ||
365 ques_type < 0x1b || ques_type >= 0x20 ||
366 strequal(qname, namerec->name.name)))
368 /* Start with the name. */
369 memset(buf,'\0',18);
370 slprintf(buf, 17, "%-15.15s",namerec->name.name);
371 strupper(buf);
373 /* Put the name type and netbios flags in the buffer. */
374 buf[15] = name_type;
375 set_nb_flags( &buf[16],namerec->data.nb_flags );
376 buf[16] |= NB_ACTIVE; /* all our names are active */
378 buf += 18;
380 names_added++;
384 /* Remove duplicate names. */
385 if (names_added > 1) {
386 qsort( buf0, names_added, 18, QSORT_CAST status_compare );
389 for( i=1; i < names_added ; i++ )
391 if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0)
393 names_added--;
394 if (names_added == i)
395 break;
396 memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
397 i--;
401 buf = buf0 + 18*names_added;
403 namerec = (struct name_record *)ubi_trNext( namerec );
405 if (!namerec)
407 /* End of the subnet specific name list. Now
408 add the names on the unicast subnet . */
409 struct subnet_record *uni_subrec = unicast_subnet;
411 if (uni_subrec != subrec)
413 subrec = uni_subrec;
414 namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
417 if (!namerec)
418 break;
422 SCVAL(countptr,0,names_added);
424 /* We don't send any stats as they could be used to attack
425 the protocol. */
426 memset(buf,'\0',46);
428 buf += 46;
430 /* Send a NODE STATUS RESPONSE */
431 reply_netbios_packet(p, /* Packet to reply to. */
432 0, /* Result code. */
433 NMB_STATUS, /* nmbd type code. */
434 NMB_NAME_QUERY_OPCODE, /* opcode. */
435 0, /* ttl. */
436 rdata, /* data to send. */
437 PTR_DIFF(buf,rdata)); /* data length. */
441 /***************************************************************************
442 Process a name query.
444 For broadcast name queries:
446 - Only reply if the query is for one of YOUR names.
447 - NEVER send a negative response to a broadcast query.
449 ****************************************************************************/
451 void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
453 struct nmb_packet *nmb = &p->packet.nmb;
454 struct nmb_name *question = &nmb->question.question_name;
455 int name_type = question->name_type;
456 BOOL bcast = nmb->header.nm_flags.bcast;
457 int ttl=0;
458 int rcode = 0;
459 char *prdata = NULL;
460 char rdata[6];
461 BOOL success = False;
462 struct name_record *namerec = NULL;
463 int reply_data_len = 0;
464 int i;
466 DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
467 inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
469 /* Look up the name in the cache - if the request is a broadcast request that
470 came from a subnet we don't know about then search all the broadcast subnets
471 for a match (as we don't know what interface the request came in on). */
473 if(subrec == remote_broadcast_subnet)
474 namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
475 else
476 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
479 /* Check if it is a name that expired */
480 if( namerec
481 && ( (namerec->data.death_time != PERMANENT_TTL)
482 && (namerec->data.death_time < p->timestamp) ) )
484 DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
485 namerec = NULL;
488 if (namerec)
492 * Always respond to unicast queries.
493 * Don't respond to broadcast queries unless the query is for
494 * a name we own, a Primary Domain Controller name, or a WINS_PROXY
495 * name with type 0 or 0x20. WINS_PROXY names are only ever added
496 * into the namelist if we were configured as a WINS proxy.
499 if( !bcast
500 || ( bcast
501 && ( (name_type == 0x1b)
502 || (namerec->data.source == SELF_NAME)
503 || (namerec->data.source == PERMANENT_NAME)
504 || ( (namerec->data.source == WINS_PROXY_NAME)
505 && ( (name_type == 0) || (name_type == 0x20) )
512 /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
513 or it's a Domain Master type. */
516 * If this is a WINS_PROXY_NAME, then ceck that none of the IP
517 * addresses we are returning is on the same broadcast subnet
518 * as the requesting packet. If it is then don't reply as the
519 * actual machine will be replying also and we don't want two
520 * replies to a broadcast query.
523 if( namerec->data.source == WINS_PROXY_NAME )
525 for( i = 0; i < namerec->data.num_ips; i++)
527 if(same_net( namerec->data.ip[i], subrec->myip, subrec->mask_ip ))
529 DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also \
530 on the same subnet (%s) as the requestor. Not replying.\n",
531 nmb_namestr(&namerec->name), subrec->subnet_name ));
532 return;
537 ttl = (namerec->data.death_time != PERMANENT_TTL) ?
538 namerec->data.death_time - p->timestamp : lp_max_ttl();
540 /* Copy all known ip addresses into the return data. */
541 /* Optimise for the common case of one IP address so
542 we don't need a malloc. */
544 if( namerec->data.num_ips == 1 )
545 prdata = rdata;
546 else
548 if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL)
550 DEBUG(0,("process_name_query_request: malloc fail !\n"));
551 return;
555 for( i = 0; i < namerec->data.num_ips; i++ )
557 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
558 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
561 sort_query_replies(prdata, i, p->ip);
563 reply_data_len = namerec->data.num_ips * 6;
564 success = True;
569 * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
570 * set we should initiate a WINS query here. On success we add the resolved name
571 * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
574 if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
575 bcast && (subrec != remote_broadcast_subnet))
577 make_wins_proxy_name_query_request( subrec, p, question );
578 return;
581 if (!success && bcast)
583 if(prdata != rdata)
584 SAFE_FREE(prdata);
585 return; /* Never reply with a negative response to broadcasts. */
589 * Final check. From observation, if a unicast packet is sent
590 * to a non-WINS server with the recursion desired bit set
591 * then never send a negative response.
594 if(!success && !bcast && nmb->header.nm_flags.recursion_desired)
596 if(prdata != rdata)
597 SAFE_FREE(prdata);
598 return;
601 if (success)
603 rcode = 0;
604 DEBUG(3,("OK\n"));
606 else
608 rcode = NAM_ERR;
609 DEBUG(3,("UNKNOWN\n"));
612 /* See rfc1002.txt 4.2.13. */
614 reply_netbios_packet(p, /* Packet to reply to. */
615 rcode, /* Result code. */
616 NMB_QUERY, /* nmbd type code. */
617 NMB_NAME_QUERY_OPCODE, /* opcode. */
618 ttl, /* ttl. */
619 prdata, /* data to send. */
620 reply_data_len); /* data length. */
622 if(prdata != rdata)
623 SAFE_FREE(prdata);