2 Unix SMB/Netbios implementation.
4 NBT netbios library routines
5 Copyright (C) Andrew Tridgell 1994-1995
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int ClientDGRAM;
28 extern struct subnet_record *subnetlist;
30 extern int DEBUGLEVEL;
32 static uint16 name_trn_id=0;
33 BOOL CanRecurse = True;
35 extern pstring myname;
36 extern struct in_addr ipzero;
37 extern struct in_addr ipgrp;
39 int num_response_packets = 0;
41 /***************************************************************************
42 updates the unique transaction identifier
43 **************************************************************************/
44 static void update_name_trn_id(void)
48 name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100);
50 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
54 /***************************************************************************
55 add an expected response record into the list
56 **************************************************************************/
57 static void add_response_record(struct subnet_record *d,
58 struct response_record *n)
60 struct response_record *n2;
72 for (n2 = d->responselist; n2->next; n2 = n2->next) ;
80 /***************************************************************************
81 remove an expected response record from the list
82 **************************************************************************/
83 static void remove_response_record(struct subnet_record *d,
84 struct response_record *n)
86 if (n->prev) n->prev->next = n->next;
87 if (n->next) n->next->prev = n->prev;
89 if (d->responselist == n) d->responselist = n->next;
95 /***************************************************************************
96 deals with an entry before it dies
97 **************************************************************************/
98 static void dead_netbios_entry(struct subnet_record *d,
99 struct response_record *n)
101 DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
102 inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
106 case NAME_QUERY_CONFIRM:
108 if (!lp_wins_support()) return; /* only if we're a WINS server */
110 if (n->num_msgs == 0)
112 /* oops. name query had no response. check that the name is
113 unique and then remove it from our WINS database */
115 /* IMPORTANT: see query_refresh_names() */
117 if ((!NAME_GROUP(n->nb_flags)))
119 struct subnet_record *d1 = find_subnet(ipgrp);
122 /* remove the name that had been registered with us,
123 and we're now getting no response when challenging.
124 see rfc1001.txt 15.5.2
126 remove_netbios_name(d1, n->name.name, n->name.name_type,
134 case NAME_QUERY_MST_CHK:
136 /* if no response received, the master browser must have gone
137 down on that subnet, without telling anyone. */
139 /* IMPORTANT: see response_netbios_packet() */
141 if (n->num_msgs == 0)
142 browser_gone(n->name.name, n->to_ip);
148 /* if no response received, it must be OK for us to release the
149 name. nobody objected (including a potentially dead or deaf
152 /* IMPORTANT: see response_name_release() */
154 if (ismyip(n->to_ip))
156 name_unregister_work(d,n->name.name,n->name.name_type);
160 DEBUG(0,("WINS server did not respond to name release!\n"));
161 /* XXXX whoops. we have problems. must deal with this */
168 /* if no response received, and we are using a broadcast registration
169 method, it must be OK for us to register the name: nobody objected
170 on that subnet. if we are using a WINS server, then the WINS
171 server must be dead or deaf.
175 /* broadcast method: implicit acceptance of the name registration
176 by not receiving any objections. */
178 /* IMPORTANT: see response_name_reg() */
180 name_register_work(d,n->name.name,n->name.name_type,
181 n->nb_flags, n->ttl, n->to_ip, n->bcast);
185 /* XXXX oops. this is where i wish this code could retry DGRAM
186 packets. we directed a name registration at a WINS server, and
187 received no response. rfc1001.txt states that after retrying,
188 we should assume the WINS server is dead, and fall back to
191 DEBUG(1,("WINS server did not respond to name registration!\n"));
192 /* XXXX whoops. we have problems. must deal with this */
199 /* nothing to do but delete the dead expected-response structure */
200 /* this is normal. */
207 /****************************************************************************
208 initiate a netbios packet
209 ****************************************************************************/
210 static void initiate_netbios_packet(uint16 *id,
211 int fd,int quest_type,char *name,int name_type,
212 int nb_flags,BOOL bcast,BOOL recurse,
213 struct in_addr to_ip)
215 struct packet_struct p;
216 struct nmb_packet *nmb = &p.packet.nmb;
217 struct res_rec additional_rec;
218 char *packet_type = "unknown";
223 if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
224 if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
225 if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
226 if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
228 DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
229 packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
231 if (opcode == -1) return;
233 bzero((char *)&p,sizeof(p));
235 update_name_trn_id();
237 if (*id == 0xffff) *id = name_trn_id; /* allow resending with same id */
239 nmb->header.name_trn_id = *id;
240 nmb->header.opcode = opcode;
241 nmb->header.response = False;
242 nmb->header.nm_flags.bcast = bcast;
243 nmb->header.nm_flags.recursion_available = CanRecurse;
244 nmb->header.nm_flags.recursion_desired = recurse;
245 nmb->header.nm_flags.trunc = False;
246 nmb->header.nm_flags.authoritative = False;
247 nmb->header.rcode = 0;
248 nmb->header.qdcount = 1;
249 nmb->header.ancount = 0;
250 nmb->header.nscount = 0;
251 nmb->header.arcount = (quest_type==NMB_REG || quest_type==NMB_REL) ? 1 : 0;
253 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
255 nmb->question.question_type = quest_type;
256 nmb->question.question_class = 0x1;
258 if (quest_type == NMB_REG || quest_type == NMB_REL)
260 nmb->additional = &additional_rec;
261 bzero((char *)nmb->additional,sizeof(*nmb->additional));
263 nmb->additional->rr_name = nmb->question.question_name;
264 nmb->additional->rr_type = nmb->question.question_type;
265 nmb->additional->rr_class = nmb->question.question_class;
267 nmb->additional->ttl = quest_type == NMB_REG ? lp_max_ttl() : 0;
268 nmb->additional->rdlength = 6;
269 nmb->additional->rdata[0] = nb_flags;
270 putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip));
276 p.timestamp = time(NULL);
277 p.packet_type = NMB_PACKET;
279 if (!send_packet(&p)) *id = 0xffff;
285 /*******************************************************************
286 remove old name response entries
287 XXXX retry code needs to be added, including a retry wait period and a count
288 see name_query() and name_status() for suggested implementation.
289 ******************************************************************/
290 void expire_netbios_response_entries()
292 struct response_record *n;
293 struct response_record *nextn;
294 struct subnet_record *d;
296 for (d = subnetlist; d; d = d->next)
297 for (n = d->responselist; n; n = nextn)
299 if (n->repeat_time < time(NULL))
301 if (n->repeat_count > 0)
303 /* resend the entry */
304 initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
305 n->name.name, n->name.name_type,
306 n->nb_flags, n->bcast, n->recurse, n->to_ip);
308 n->repeat_time += n->repeat_interval; /* XXXX ms needed */
314 num_response_packets--;
316 dead_netbios_entry (d,n); /* process the non-response */
317 remove_response_record(d,n); /* remove the non-response */
327 /****************************************************************************
328 reply to a netbios name packet
329 ****************************************************************************/
330 void reply_netbios_packet(struct packet_struct *p1,int trn_id,
331 int rcode,int opcode, BOOL recurse,
332 struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
335 struct packet_struct p;
336 struct nmb_packet *nmb = &p.packet.nmb;
337 struct res_rec answers;
338 char *packet_type = "unknown";
342 if (rr_type == NMB_STATUS) packet_type = "nmb_status";
343 if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
344 if (rr_type == NMB_REG ) packet_type = "nmb_reg";
345 if (rr_type == NMB_REL ) packet_type = "nmb_rel";
347 DEBUG(4,("replying netbios packet: %s %s\n",
348 packet_type, namestr(rr_name), inet_ntoa(p.ip)));
350 nmb->header.name_trn_id = trn_id;
351 nmb->header.opcode = opcode;
352 nmb->header.response = True;
353 nmb->header.nm_flags.bcast = False;
354 nmb->header.nm_flags.recursion_available = recurse;
355 nmb->header.nm_flags.recursion_desired = True;
356 nmb->header.nm_flags.trunc = False;
357 nmb->header.nm_flags.authoritative = True;
359 nmb->header.qdcount = 0;
360 nmb->header.ancount = 1;
361 nmb->header.nscount = 0;
362 nmb->header.arcount = 0;
363 nmb->header.rcode = 0;
365 bzero((char*)&nmb->question,sizeof(nmb->question));
367 nmb->answers = &answers;
368 bzero((char*)nmb->answers,sizeof(*nmb->answers));
370 nmb->answers->rr_name = *rr_name;
371 nmb->answers->rr_type = rr_type;
372 nmb->answers->rr_class = rr_class;
373 nmb->answers->ttl = ttl;
377 nmb->answers->rdlength = len;
378 memcpy(nmb->answers->rdata, data, len);
381 p.packet_type = NMB_PACKET;
383 debug_nmb_packet(&p);
389 /****************************************************************************
390 wrapper function to override a broadcast message and send it to the WINS
391 name server instead, if it exists. if wins is false, and there has been no
392 WINS server specified, the packet will NOT be sent.
393 ****************************************************************************/
394 void queue_netbios_pkt_wins(struct subnet_record *d,
395 int fd,int quest_type,enum state_type state,
396 char *name,int name_type,int nb_flags, time_t ttl,
397 BOOL bcast,BOOL recurse,struct in_addr to_ip)
399 /* XXXX note: please see rfc1001.txt section 10 for details on this
400 function: it is currently inappropriate to use this - it will do
401 for now - once there is a clarification of B, M and P nodes and
402 which one samba is supposed to be
405 if ((!lp_wins_support()) && (*lp_wins_server()))
407 /* samba is not a WINS server, and we are using a WINS server */
408 struct in_addr wins_ip;
409 wins_ip = *interpret_addr2(lp_wins_server());
411 if (!zero_ip(wins_ip))
418 /* oops. smb.conf's wins server parameter MUST be a host_name
420 DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
424 if (zero_ip(to_ip)) return;
426 queue_netbios_packet(d,fd, quest_type, state,
427 name, name_type, nb_flags, ttl,
428 bcast, recurse, to_ip);
431 /****************************************************************************
432 create a name query response record
433 **************************************************************************/
434 static struct response_record *
435 make_response_queue_record(enum state_type state,int id,int fd,
436 int quest_type, char *name,int type, int nb_flags, time_t ttl,
437 BOOL bcast,BOOL recurse, struct in_addr ip)
439 struct response_record *n;
441 if (!name || !name[0]) return NULL;
443 if (!(n = (struct response_record *)malloc(sizeof(*n))))
449 n->quest_type = quest_type;
450 make_nmb_name(&n->name, name, type, scope);
451 n->nb_flags = nb_flags;
454 n->recurse = recurse;
457 n->repeat_interval = 1; /* XXXX should be in ms */
459 n->repeat_time = time(NULL) + n->repeat_interval;
463 num_response_packets++; /* count of total number of packets still around */
469 /****************************************************************************
470 initiate a netbios name query to find someone's or someones' IP
471 this is intended to be used (not exclusively) for broadcasting to
472 master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
473 complete lists across a wide area network
474 ****************************************************************************/
475 void queue_netbios_packet(struct subnet_record *d,
476 int fd,int quest_type,enum state_type state,char *name,
477 int name_type,int nb_flags, time_t ttl,
478 BOOL bcast,BOOL recurse, struct in_addr to_ip)
480 struct in_addr wins_ip = ipgrp;
481 struct response_record *n;
484 /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
485 if (ip_equal(wins_ip, to_ip)) return;
487 initiate_netbios_packet(&id, fd, quest_type, name, name_type,
488 nb_flags, bcast, recurse, to_ip);
490 if (id == 0xffff) return;
492 if ((n = make_response_queue_record(state,id,fd,
493 quest_type,name,name_type,nb_flags,ttl,
494 bcast,recurse,to_ip)))
496 add_response_record(d,n);
501 /****************************************************************************
502 find a response in a subnet's name query response list.
503 **************************************************************************/
504 struct response_record *find_response_record(struct subnet_record **d,
507 struct response_record *n;
511 for ((*d) = subnetlist; (*d); (*d) = (*d)->next)
513 for (n = (*d)->responselist; n; n = n->next)
515 if (n->response_id == id) {
527 /*******************************************************************
528 the global packet linked-list. incoming entries are added to the
529 end of this list. it is supposed to remain fairly short so we
530 won't bother with an end pointer.
531 ******************************************************************/
532 static struct packet_struct *packet_queue = NULL;
534 /*******************************************************************
535 queue a packet into the packet queue
536 ******************************************************************/
537 void queue_packet(struct packet_struct *packet)
539 struct packet_struct *p;
544 packet_queue = packet;
548 /* find the bottom */
549 for (p=packet_queue;p->next;p=p->next) ;
556 /*******************************************************************
557 run elements off the packet queue till its empty
558 ******************************************************************/
559 void run_packet_queue()
561 struct packet_struct *p;
563 while ((p=packet_queue))
565 switch (p->packet_type)
576 packet_queue = packet_queue->next;
577 if (packet_queue) packet_queue->prev = NULL;
582 /****************************************************************************
583 listens for NMB or DGRAM packets, and queues them
584 ***************************************************************************/
585 void listen_for_packets(BOOL run_election)
589 struct timeval timeout;
592 FD_SET(ClientNMB,&fds);
593 FD_SET(ClientDGRAM,&fds);
595 /* during elections and when expecting a netbios response packet we need
596 to send election packets at one second intervals.
597 XXXX actually, it needs to be the interval (in ms) between time now and the
598 time we are expecting the next netbios packet */
600 timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
603 selrtn = sys_select(&fds,&timeout);
605 if (FD_ISSET(ClientNMB,&fds))
607 struct packet_struct *packet = read_packet(ClientNMB, NMB_PACKET);
610 if (ismyip(packet->ip) &&
611 (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
612 DEBUG(5,("discarding own packet from %s:%d\n",
613 inet_ntoa(packet->ip),packet->port));
618 queue_packet(packet);
623 if (FD_ISSET(ClientDGRAM,&fds))
625 struct packet_struct *packet = read_packet(ClientDGRAM, DGRAM_PACKET);
628 if (ismyip(packet->ip) &&
629 (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
630 DEBUG(5,("discarding own packet from %s:%d\n",
631 inet_ntoa(packet->ip),packet->port));
636 queue_packet(packet);
644 /****************************************************************************
645 interpret a node status response. this is pretty hacked: we need two bits of
646 info. a) the name of the workgroup b) the name of the server. it will also
647 add all the names it finds into the namelist.
648 ****************************************************************************/
649 BOOL interpret_node_status(struct subnet_record *d,
650 char *p, struct nmb_name *name,int t,
651 char *serv_name, struct in_addr ip, BOOL bcast)
653 int level = t==0x20 ? 4 : 0;
654 int numnames = CVAL(p,0);
657 DEBUG(level,("received %d names\n",numnames));
661 if (serv_name) *serv_name = 0;
678 trim_string(qname,NULL," ");
682 if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
683 if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
684 if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
685 if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
686 if (NAME__FLAG (nb_flags)) { strcat(flags,"_ "); }
687 if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
688 if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
689 if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
690 if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
692 /* might as well update our namelist while we're at it */
695 struct in_addr nameip;
696 enum name_source src;
705 add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
708 /* we want the server name */
709 if (serv_name && !*serv_name && !group && t == 0)
711 StrnCpy(serv_name,qname,15);
715 /* looking for a name and type? */
716 if (name && !found && (t == type))
718 /* take a guess at some of the name types we're going to ask for.
719 evaluate whether they are group names or no... */
720 if (((t == 0x1b || t == 0x1d ) && !group) ||
721 ((t == 0x20 || t == 0x1c || t == 0x1e) && group))
724 make_nmb_name(name,qname,type,scope);
728 DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags));
730 DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
731 IVAL(p,20),IVAL(p,24)));
736 /****************************************************************************
737 construct and send a netbios DGRAM
739 Note that this currently sends all answers to port 138. thats the
740 wrong things to do! I should send to the requestors port. XXX
741 **************************************************************************/
742 BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
743 char *dstname,int src_type,int dest_type,
744 struct in_addr dest_ip,struct in_addr src_ip)
746 struct packet_struct p;
747 struct dgram_packet *dgram = &p.packet.dgram;
748 struct in_addr wins_ip = ipgrp;
752 /* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
753 if (ip_equal(wins_ip, dest_ip)) return False;
755 bzero((char *)&p,sizeof(p));
757 update_name_trn_id();
759 dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
760 dgram->header.flags.node_type = M_NODE;
761 dgram->header.flags.first = True;
762 dgram->header.flags.more = False;
763 dgram->header.dgm_id = name_trn_id;
764 dgram->header.source_ip = src_ip;
765 dgram->header.source_port = DGRAM_PORT;
766 dgram->header.dgm_length = 0; /* let build_dgram() handle this */
767 dgram->header.packet_offset = 0;
769 make_nmb_name(&dgram->source_name,srcname,src_type,scope);
770 make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
772 ptr = &dgram->data[0];
774 /* now setup the smb part */
775 ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
777 set_message(ptr,17,17 + len,True);
780 CVAL(ptr,smb_com) = SMBtrans;
781 SSVAL(ptr,smb_vwv1,len);
782 SSVAL(ptr,smb_vwv11,len);
783 SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
784 SSVAL(ptr,smb_vwv13,3);
785 SSVAL(ptr,smb_vwv14,1);
786 SSVAL(ptr,smb_vwv15,1);
787 SSVAL(ptr,smb_vwv16,2);
790 p2 = skip_string(p2,1);
795 dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
800 p.timestamp = time(NULL);
801 p.packet_type = DGRAM_PACKET;
803 return(send_packet(&p));