s3-nmbd: note TODO item for qsort
[Samba/cd1.git] / source3 / nmbd / nmbd_incomingrequests.c
blob6d8436d9e38251fd88b1faadd18d11b74c10998e
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
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.
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.
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/>.
21 This file contains all the code to process NetBIOS requests coming
22 in on port 137. It does not deal with the code needed to service
23 WINS server requests, but only broadcast and unicast requests.
27 #include "includes.h"
29 /****************************************************************************
30 Send a name release response.
31 **************************************************************************/
33 static void send_name_release_response(int rcode, struct packet_struct *p)
35 struct nmb_packet *nmb = &p->packet.nmb;
36 char rdata[6];
38 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
40 reply_netbios_packet(p, /* Packet to reply to. */
41 rcode, /* Result code. */
42 NMB_REL, /* nmbd type code. */
43 NMB_NAME_RELEASE_OPCODE, /* opcode. */
44 0, /* ttl. */
45 rdata, /* data to send. */
46 6); /* data length. */
49 /****************************************************************************
50 Process a name release packet on a broadcast subnet.
51 Ignore it if it's not one of our names.
52 ****************************************************************************/
54 void process_name_release_request(struct subnet_record *subrec,
55 struct packet_struct *p)
57 struct nmb_packet *nmb = &p->packet.nmb;
58 struct in_addr owner_ip;
59 struct nmb_name *question = &nmb->question.question_name;
60 unstring qname;
61 bool bcast = nmb->header.nm_flags.bcast;
62 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
63 bool group = (nb_flags & NB_GROUP) ? True : False;
64 struct name_record *namerec;
65 int rcode = 0;
67 putip((char *)&owner_ip,&nmb->additional->rdata[2]);
69 if(!bcast) {
70 /* We should only get broadcast name release packets here.
71 Anyone trying to release unicast should be going to a WINS
72 server. If the code gets here, then either we are not a wins
73 server and they sent it anyway, or we are a WINS server and
74 the request was malformed. Either way, log an error here.
75 and send an error reply back.
77 DEBUG(0,("process_name_release_request: unicast name release request \
78 received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
79 nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
81 send_name_release_response(FMT_ERR, p);
82 return;
85 DEBUG(3,("process_name_release_request: Name release on name %s, \
86 subnet %s from owner IP %s\n",
87 nmb_namestr(&nmb->question.question_name),
88 subrec->subnet_name, inet_ntoa(owner_ip)));
90 /* If someone is releasing a broadcast group name, just ignore it. */
91 if( group && !ismyip_v4(owner_ip) )
92 return;
95 * Code to work around a bug in FTP OnNet software NBT implementation.
96 * They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
97 * names and *don't set the group bit* !!!!!
100 pull_ascii_nstring(qname, sizeof(qname), question->name);
101 if( !group && !ismyip_v4(owner_ip) && strequal(qname, lp_workgroup()) &&
102 ((question->name_type == 0x0) || (question->name_type == 0x1e))) {
103 DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
104 group release name %s from IP %s on subnet %s with no group bit set.\n",
105 nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
106 return;
109 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
111 /* We only care about someone trying to release one of our names. */
112 if( namerec && ( (namerec->data.source == SELF_NAME)
113 || (namerec->data.source == PERMANENT_NAME) ) ) {
114 rcode = ACT_ERR;
115 DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
116 on subnet %s being rejected as it is one of our names.\n",
117 nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
120 if(rcode == 0)
121 return;
123 /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
124 send_name_release_response(rcode, p);
127 /****************************************************************************
128 Send a name registration response.
129 **************************************************************************/
131 static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
133 struct nmb_packet *nmb = &p->packet.nmb;
134 char rdata[6];
136 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
138 reply_netbios_packet(p, /* Packet to reply to. */
139 rcode, /* Result code. */
140 NMB_REG, /* nmbd type code. */
141 NMB_NAME_REG_OPCODE, /* opcode. */
142 ttl, /* ttl. */
143 rdata, /* data to send. */
144 6); /* data length. */
147 /****************************************************************************
148 Process a name refresh request on a broadcast subnet.
149 **************************************************************************/
151 void process_name_refresh_request(struct subnet_record *subrec,
152 struct packet_struct *p)
154 struct nmb_packet *nmb = &p->packet.nmb;
155 struct nmb_name *question = &nmb->question.question_name;
156 bool bcast = nmb->header.nm_flags.bcast;
157 struct in_addr from_ip;
159 putip((char *)&from_ip,&nmb->additional->rdata[2]);
161 if(!bcast) {
162 /* We should only get broadcast name refresh packets here.
163 Anyone trying to refresh unicast should be going to a WINS
164 server. If the code gets here, then either we are not a wins
165 server and they sent it anyway, or we are a WINS server and
166 the request was malformed. Either way, log an error here.
167 and send an error reply back.
169 DEBUG(0,("process_name_refresh_request: unicast name registration request \
170 received for name %s from IP %s on subnet %s.\n",
171 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
172 DEBUG(0,("Error - should be sent to WINS server\n"));
174 send_name_registration_response(FMT_ERR, 0, p);
175 return;
178 /* Just log a message. We really don't care about broadcast name refreshes. */
180 DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
181 IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
184 /****************************************************************************
185 Process a name registration request on a broadcast subnet.
186 **************************************************************************/
188 void process_name_registration_request(struct subnet_record *subrec,
189 struct packet_struct *p)
191 struct nmb_packet *nmb = &p->packet.nmb;
192 struct nmb_name *question = &nmb->question.question_name;
193 bool bcast = nmb->header.nm_flags.bcast;
194 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
195 bool group = (nb_flags & NB_GROUP) ? True : False;
196 struct name_record *namerec = NULL;
197 int ttl = nmb->additional->ttl;
198 struct in_addr from_ip;
200 putip((char *)&from_ip,&nmb->additional->rdata[2]);
202 if(!bcast) {
203 /* We should only get broadcast name registration packets here.
204 Anyone trying to register unicast should be going to a WINS
205 server. If the code gets here, then either we are not a wins
206 server and they sent it anyway, or we are a WINS server and
207 the request was malformed. Either way, log an error here.
208 and send an error reply back.
210 DEBUG(0,("process_name_registration_request: unicast name registration request \
211 received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
212 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
214 send_name_registration_response(FMT_ERR, 0, p);
215 return;
218 DEBUG(3,("process_name_registration_request: Name registration for name %s \
219 IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
221 /* See if the name already exists. */
222 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
225 * If the name being registered exists and is a WINS_PROXY_NAME
226 * then delete the WINS proxy name entry so we don't reply erroneously
227 * later to queries.
230 if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME)) {
231 remove_name_from_namelist( subrec, namerec );
232 namerec = NULL;
235 if (!group) {
236 /* Unique name. */
238 if( (namerec != NULL)
239 && ( (namerec->data.source == SELF_NAME)
240 || (namerec->data.source == PERMANENT_NAME)
241 || NAME_GROUP(namerec) ) ) {
242 /* No-one can register one of Samba's names, nor can they
243 register a name that's a group name as a unique name */
245 send_name_registration_response(ACT_ERR, 0, p);
246 return;
247 } else if(namerec != NULL) {
248 /* Update the namelist record with the new information. */
249 namerec->data.ip[0] = from_ip;
250 update_name_ttl(namerec, ttl);
252 DEBUG(3,("process_name_registration_request: Updated name record %s \
253 with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
254 return;
256 } else {
257 /* Group name. */
259 if( (namerec != NULL)
260 && !NAME_GROUP(namerec)
261 && ( (namerec->data.source == SELF_NAME)
262 || (namerec->data.source == PERMANENT_NAME) ) ) {
263 /* Disallow group names when we have a unique name. */
264 send_name_registration_response(ACT_ERR, 0, p);
265 return;
270 /****************************************************************************
271 This is used to sort names for a name status into a sensible order.
272 We put our own names first, then in alphabetical order.
273 **************************************************************************/
275 static int status_compare(char *n1,char *n2)
277 unstring name1, name2;
278 int l1,l2,l3;
280 memset(name1, '\0', sizeof(name1));
281 memset(name2, '\0', sizeof(name2));
282 pull_ascii_nstring(name1, sizeof(name1), n1);
283 pull_ascii_nstring(name2, sizeof(name2), n2);
284 n1 = name1;
285 n2 = name2;
287 /* It's a bit tricky because the names are space padded */
288 for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++)
290 for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++)
292 l3 = strlen(global_myname());
294 if ((l1==l3) && strncmp(n1,global_myname(),l3) == 0 &&
295 (l2!=l3 || strncmp(n2,global_myname(),l3) != 0))
296 return -1;
298 if ((l2==l3) && strncmp(n2,global_myname(),l3) == 0 &&
299 (l1!=l3 || strncmp(n1,global_myname(),l3) != 0))
300 return 1;
302 return memcmp(n1,n2,sizeof(name1));
305 /****************************************************************************
306 Process a node status query
307 ****************************************************************************/
309 void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
311 struct nmb_packet *nmb = &p->packet.nmb;
312 unstring qname;
313 int ques_type = nmb->question.question_name.name_type;
314 char rdata[MAX_DGRAM_SIZE];
315 char *countptr, *buf, *bufend, *buf0;
316 int names_added,i;
317 struct name_record *namerec = NULL;
319 pull_ascii_nstring(qname, sizeof(qname), nmb->question.question_name.name);
321 DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
322 subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
324 if(find_name_on_subnet(subrec, &nmb->question.question_name, FIND_SELF_NAME) == 0) {
325 DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
326 subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
327 inet_ntoa(p->ip), subrec->subnet_name));
329 return;
332 /* this is not an exact calculation. the 46 is for the stats buffer
333 and the 60 is to leave room for the header etc */
334 bufend = &rdata[MAX_DGRAM_SIZE-1] - (18 + 46 + 60);
335 countptr = buf = rdata;
336 buf += 1;
337 buf0 = buf;
339 names_added = 0;
341 namerec = subrec->namelist;
343 while (buf < bufend) {
344 if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) {
345 int name_type = namerec->name.name_type;
346 unstring name;
348 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
349 strupper_m(name);
350 if (!strequal(name,"*") &&
351 !strequal(name,"__SAMBA__") &&
352 (name_type < 0x1b || name_type >= 0x20 ||
353 ques_type < 0x1b || ques_type >= 0x20 ||
354 strequal(qname, name))) {
355 /* Start with the name. */
356 size_t len;
357 push_ascii_nstring(buf, name);
358 len = strlen(buf);
359 memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - len - 1);
360 buf[MAX_NETBIOSNAME_LEN - 1] = '\0';
362 /* Put the name type and netbios flags in the buffer. */
364 buf[15] = name_type;
365 set_nb_flags( &buf[16],namerec->data.nb_flags );
366 buf[16] |= NB_ACTIVE; /* all our names are active */
368 buf += 18;
370 names_added++;
374 /* Remove duplicate names. */
375 if (names_added > 1) {
376 /* TODO: should use a real type and
377 TYPESAFE_QSORT() */
378 qsort( buf0, names_added, 18, QSORT_CAST status_compare );
381 for( i=1; i < names_added ; i++ ) {
382 if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
383 names_added--;
384 if (names_added == i)
385 break;
386 memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
387 i--;
391 buf = buf0 + 18*names_added;
393 namerec = namerec->next;
395 if (!namerec) {
396 /* End of the subnet specific name list. Now
397 add the names on the unicast subnet . */
398 struct subnet_record *uni_subrec = unicast_subnet;
400 if (uni_subrec != subrec) {
401 subrec = uni_subrec;
402 namerec = subrec->namelist;
405 if (!namerec)
406 break;
410 SCVAL(countptr,0,names_added);
412 /* We don't send any stats as they could be used to attack
413 the protocol. */
414 memset(buf,'\0',46);
416 buf += 46;
418 /* Send a NODE STATUS RESPONSE */
419 reply_netbios_packet(p, /* Packet to reply to. */
420 0, /* Result code. */
421 NMB_STATUS, /* nmbd type code. */
422 NMB_NAME_QUERY_OPCODE, /* opcode. */
423 0, /* ttl. */
424 rdata, /* data to send. */
425 PTR_DIFF(buf,rdata)); /* data length. */
429 /***************************************************************************
430 Process a name query.
432 For broadcast name queries:
434 - Only reply if the query is for one of YOUR names.
435 - NEVER send a negative response to a broadcast query.
437 ****************************************************************************/
439 void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
441 struct nmb_packet *nmb = &p->packet.nmb;
442 struct nmb_name *question = &nmb->question.question_name;
443 int name_type = question->name_type;
444 bool bcast = nmb->header.nm_flags.bcast;
445 int ttl=0;
446 int rcode = 0;
447 char *prdata = NULL;
448 char rdata[6];
449 bool success = False;
450 struct name_record *namerec = NULL;
451 int reply_data_len = 0;
452 int i;
454 DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
455 inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
457 /* Look up the name in the cache - if the request is a broadcast request that
458 came from a subnet we don't know about then search all the broadcast subnets
459 for a match (as we don't know what interface the request came in on). */
461 if(subrec == remote_broadcast_subnet)
462 namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
463 else
464 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
466 /* Check if it is a name that expired */
467 if (namerec &&
468 ((namerec->data.death_time != PERMANENT_TTL) &&
469 (namerec->data.death_time < p->timestamp))) {
470 DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
471 namerec = NULL;
474 if (namerec) {
476 * Always respond to unicast queries.
477 * Don't respond to broadcast queries unless the query is for
478 * a name we own, a Primary Domain Controller name, or a WINS_PROXY
479 * name with type 0 or 0x20. WINS_PROXY names are only ever added
480 * into the namelist if we were configured as a WINS proxy.
483 if (!bcast ||
484 (bcast && ((name_type == 0x1b) ||
485 (namerec->data.source == SELF_NAME) ||
486 (namerec->data.source == PERMANENT_NAME) ||
487 ((namerec->data.source == WINS_PROXY_NAME) &&
488 ((name_type == 0) || (name_type == 0x20)))))) {
489 /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
490 or it's a Domain Master type. */
493 * If this is a WINS_PROXY_NAME, then ceck that none of the IP
494 * addresses we are returning is on the same broadcast subnet
495 * as the requesting packet. If it is then don't reply as the
496 * actual machine will be replying also and we don't want two
497 * replies to a broadcast query.
500 if (namerec->data.source == WINS_PROXY_NAME) {
501 for( i = 0; i < namerec->data.num_ips; i++) {
502 if (same_net_v4(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) {
503 DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying.\n",
504 nmb_namestr(&namerec->name), subrec->subnet_name ));
505 return;
510 ttl = (namerec->data.death_time != PERMANENT_TTL) ?
511 namerec->data.death_time - p->timestamp : lp_max_ttl();
513 /* Copy all known ip addresses into the return data. */
514 /* Optimise for the common case of one IP address so
515 we don't need a malloc. */
517 if (namerec->data.num_ips == 1) {
518 prdata = rdata;
519 } else {
520 if ((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
521 DEBUG(0,("process_name_query_request: malloc fail !\n"));
522 return;
526 for (i = 0; i < namerec->data.num_ips; i++) {
527 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
528 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
531 sort_query_replies(prdata, i, p->ip);
533 reply_data_len = namerec->data.num_ips * 6;
534 success = True;
539 * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
540 * set we should initiate a WINS query here. On success we add the resolved name
541 * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
544 if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
545 bcast && (subrec != remote_broadcast_subnet)) {
546 make_wins_proxy_name_query_request( subrec, p, question );
547 return;
550 if (!success && bcast) {
551 if(prdata != rdata)
552 SAFE_FREE(prdata);
553 return; /* Never reply with a negative response to broadcasts. */
557 * Final check. From observation, if a unicast packet is sent
558 * to a non-WINS server with the recursion desired bit set
559 * then never send a negative response.
562 if(!success && !bcast && nmb->header.nm_flags.recursion_desired) {
563 if(prdata != rdata)
564 SAFE_FREE(prdata);
565 return;
568 if (success) {
569 rcode = 0;
570 DEBUG(3,("OK\n"));
571 } else {
572 rcode = NAM_ERR;
573 DEBUG(3,("UNKNOWN\n"));
576 /* See rfc1002.txt 4.2.13. */
578 reply_netbios_packet(p, /* Packet to reply to. */
579 rcode, /* Result code. */
580 NMB_QUERY, /* nmbd type code. */
581 NMB_NAME_QUERY_OPCODE, /* opcode. */
582 ttl, /* ttl. */
583 prdata, /* data to send. */
584 reply_data_len); /* data length. */
586 if(prdata != rdata)
587 SAFE_FREE(prdata);