2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1994-1998
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.
25 extern int DEBUGLEVEL;
27 /* nmbd.c sets this to True. */
28 BOOL global_in_nmbd = False;
30 /****************************************************************************
31 generate a random trn_id
32 ****************************************************************************/
33 static int generate_trn_id(void)
38 sys_srandom(sys_getpid());
41 trn_id = sys_random();
43 return trn_id % (unsigned)0x7FFF;
47 /****************************************************************************
48 Interpret a node status response.
49 ****************************************************************************/
51 static void _interpret_node_status(char *p, char *master,char *rname)
53 int numnames = CVAL(p,0);
54 DEBUG(1,("received %d names\n",numnames));
56 if (rname) *rname = 0;
57 if (master) *master = 0;
70 fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
71 if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
72 if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
73 if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
74 if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
75 if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
76 if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
77 if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
78 if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
80 if (master && !*master && type == 0x1d) {
81 StrnCpy(master,qname,15);
82 trim_string(master,NULL," ");
85 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
86 StrnCpy(rname,qname,15);
87 trim_string(rname,NULL," ");
90 for (i = strlen( qname) ; --i >= 0 ; ) {
91 if (!isprint((int)qname[i])) qname[i] = '.';
93 DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
97 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
98 IVAL(p,20),IVAL(p,24)));
101 /****************************************************************************
102 Internal function handling a netbios name status query on a host.
103 **************************************************************************/
104 static BOOL internal_name_status(int fd,char *name,int name_type,BOOL recurse,
105 struct in_addr to_ip,char *master,
106 char *rname, BOOL verbose,
107 void (*fn_interpret_node_status)(char *, char *,char *))
111 int retry_time = 5000;
113 struct packet_struct p;
114 struct packet_struct *p2;
115 struct nmb_packet *nmb = &p.packet.nmb;
117 memset((char *)&p,'\0',sizeof(p));
119 nmb->header.name_trn_id = generate_trn_id();
120 nmb->header.opcode = 0;
121 nmb->header.response = False;
122 nmb->header.nm_flags.bcast = False;
123 nmb->header.nm_flags.recursion_available = False;
124 nmb->header.nm_flags.recursion_desired = False;
125 nmb->header.nm_flags.trunc = False;
126 nmb->header.nm_flags.authoritative = False;
127 nmb->header.rcode = 0;
128 nmb->header.qdcount = 1;
129 nmb->header.ancount = 0;
130 nmb->header.nscount = 0;
131 nmb->header.arcount = 0;
133 make_nmb_name(&nmb->question.question_name,name,name_type);
135 nmb->question.question_type = 0x21;
136 nmb->question.question_class = 0x1;
141 p.timestamp = time(NULL);
142 p.packet_type = NMB_PACKET;
146 if (!send_packet(&p))
152 struct timeval tval2;
153 GetTimeOfDay(&tval2);
154 if (TvalDiff(&tval,&tval2) > retry_time) {
157 if (!found && !send_packet(&p))
163 if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
164 struct nmb_packet *nmb2 = &p2->packet.nmb;
165 debug_nmb_packet(p2);
167 if (nmb2->header.opcode != 0 ||
168 nmb2->header.nm_flags.bcast ||
169 nmb2->header.rcode ||
170 !nmb2->header.ancount ||
171 nmb2->answers->rr_type != 0x21) {
172 /* XXXX what do we do with this? could be a
173 redirect, but we'll discard it for the
179 if(fn_interpret_node_status)
180 (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname);
187 DEBUG(0,("No status response (this is not unusual)\n"));
192 /****************************************************************************
193 Do a netbios name status query on a host.
194 The "master" parameter is a hack used for finding workgroups.
195 **************************************************************************/
196 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
197 struct in_addr to_ip,char *master,char *rname)
199 return internal_name_status(fd,name,name_type,recurse,
200 to_ip,master,rname,True,
201 _interpret_node_status);
204 /****************************************************************************
205 Do a netbios name query to find someones IP.
206 Returns an array of IP addresses or NULL if none.
207 *count will be set to the number of addresses returned.
208 ****************************************************************************/
210 struct in_addr *name_query(int fd,const char *name,int name_type,
211 BOOL bcast,BOOL recurse,
212 struct in_addr to_ip, int *count)
216 int retry_time = bcast?250:2000;
218 struct packet_struct p;
219 struct packet_struct *p2;
220 struct nmb_packet *nmb = &p.packet.nmb;
221 struct in_addr *ip_list = NULL;
223 memset((char *)&p,'\0',sizeof(p));
226 nmb->header.name_trn_id = generate_trn_id();
227 nmb->header.opcode = 0;
228 nmb->header.response = False;
229 nmb->header.nm_flags.bcast = bcast;
230 nmb->header.nm_flags.recursion_available = False;
231 nmb->header.nm_flags.recursion_desired = recurse;
232 nmb->header.nm_flags.trunc = False;
233 nmb->header.nm_flags.authoritative = False;
234 nmb->header.rcode = 0;
235 nmb->header.qdcount = 1;
236 nmb->header.ancount = 0;
237 nmb->header.nscount = 0;
238 nmb->header.arcount = 0;
240 make_nmb_name(&nmb->question.question_name,name,name_type);
242 nmb->question.question_type = 0x20;
243 nmb->question.question_class = 0x1;
248 p.timestamp = time(NULL);
249 p.packet_type = NMB_PACKET;
253 if (!send_packet(&p))
260 struct timeval tval2;
261 GetTimeOfDay(&tval2);
262 if (TvalDiff(&tval,&tval2) > retry_time) {
265 if (!found && !send_packet(&p))
271 if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
272 struct nmb_packet *nmb2 = &p2->packet.nmb;
273 debug_nmb_packet(p2);
275 if (nmb2->header.opcode != 0 ||
276 nmb2->header.nm_flags.bcast ||
277 nmb2->header.rcode ||
278 !nmb2->header.ancount) {
280 * XXXX what do we do with this? Could be a
281 * redirect, but we'll discard it for the
287 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
288 ((*count)+nmb2->answers->rdlength/6));
290 DEBUG(2,("Got a positive name query response from %s ( ",
292 for (i=0;i<nmb2->answers->rdlength/6;i++) {
293 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
294 DEBUG(2,("%s ",inet_ntoa(ip_list[(*count)])));
304 * If we're doing a unicast lookup we only
305 * expect one reply. Don't wait the full 2
306 * seconds if we got one. JRA.
316 /********************************************************
317 Start parsing the lmhosts file.
318 *********************************************************/
320 FILE *startlmhosts(char *fname)
322 FILE *fp = sys_fopen(fname,"r");
324 DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
325 fname, strerror(errno)));
331 /********************************************************
332 Parse the next line in the lmhosts file.
333 *********************************************************/
335 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
339 while(!feof(fp) && !ferror(fp)) {
340 pstring ip,flags,extra;
346 if (!fgets_slash(line,sizeof(pstring),fp))
358 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
360 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
362 if (next_token(&ptr,flags,NULL, sizeof(flags)))
364 if (next_token(&ptr,extra,NULL, sizeof(extra)))
370 if (count > 0 && count < 2)
372 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
378 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
382 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
384 if (strchr(flags,'G') || strchr(flags,'S'))
386 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
390 *ipaddr = *interpret_addr2(ip);
392 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
393 then only add that name type. */
394 if((ptr = strchr(name, '#')) != NULL)
399 *name_type = (int)strtol(ptr, &endptr, 16);
401 if(!*ptr || (endptr == ptr))
403 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
407 *(--ptr) = '\0'; /* Truncate at the '#' */
416 /********************************************************
417 Finish parsing the lmhosts file.
418 *********************************************************/
420 void endlmhosts(FILE *fp)
425 /********************************************************
426 Resolve via "bcast" method.
427 *********************************************************/
429 static BOOL resolve_bcast(const char *name, int name_type,
430 struct in_addr **return_ip_list, int *return_count)
433 int num_interfaces = iface_count();
435 *return_ip_list = NULL;
439 * "bcast" means do a broadcast lookup on all the local interfaces.
442 DEBUG(3,("resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
444 sock = open_socket_in( SOCK_DGRAM, 0, 3,
445 interpret_addr(lp_socket_address()), True );
447 if (sock == -1) return False;
449 set_socket_options(sock,"SO_BROADCAST");
451 * Lookup the name on all the interfaces, return on
452 * the first successful match.
454 for( i = num_interfaces-1; i >= 0; i--) {
455 struct in_addr sendto_ip;
456 /* Done this way to fix compiler error on IRIX 5.x */
457 sendto_ip = *iface_bcast(*iface_n_ip(i));
458 *return_ip_list = name_query(sock, name, name_type, True,
459 True, sendto_ip, return_count);
460 if(*return_ip_list != NULL) {
470 /********************************************************
471 Resolve via "wins" method.
472 *********************************************************/
474 static BOOL resolve_wins(const char *name, int name_type,
475 struct in_addr **return_iplist, int *return_count)
478 struct in_addr wins_ip;
481 *return_iplist = NULL;
485 * "wins" means do a unicast lookup to the WINS server.
486 * Ignore if there is no WINS server specified or if the
487 * WINS server is one of our interfaces (if we're being
488 * called from within nmbd - we can't do this call as we
492 DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
494 if(!*lp_wins_server()) {
495 DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS server present.\n"));
499 wins_ip = *interpret_addr2(lp_wins_server());
500 wins_ismyip = ismyip(wins_ip);
502 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
503 sock = open_socket_in( SOCK_DGRAM, 0, 3,
504 interpret_addr(lp_socket_address()), True );
507 *return_iplist = name_query(sock, name, name_type, False,
508 True, wins_ip, return_count);
509 if(*return_iplist != NULL) {
520 /********************************************************
521 Resolve via "lmhosts" method.
522 *********************************************************/
524 static BOOL resolve_lmhosts(const char *name, int name_type,
525 struct in_addr **return_iplist, int *return_count)
528 * "lmhosts" means parse the local lmhosts file.
534 struct in_addr return_ip;
536 *return_iplist = NULL;
539 DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
541 fp = startlmhosts( LMHOSTSFILE );
543 while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
544 if (strequal(name, lmhost_name) &&
545 ((name_type2 == -1) || (name_type == name_type2))
548 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
549 if(*return_iplist == NULL) {
550 DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
553 **return_iplist = return_ip;
564 /********************************************************
565 Resolve via "hosts" method.
566 *********************************************************/
568 static BOOL resolve_hosts(const char *name,
569 struct in_addr **return_iplist, int *return_count)
572 * "host" means do a localhost, or dns lookup.
576 *return_iplist = NULL;
579 DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
581 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
582 struct in_addr return_ip;
583 putip((char *)&return_ip,(char *)hp->h_addr);
584 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
585 if(*return_iplist == NULL) {
586 DEBUG(3,("resolve_hosts: malloc fail !\n"));
589 **return_iplist = return_ip;
596 /********************************************************
597 Internal interface to resolve a name into an IP address.
598 Use this function if the string is either an IP address, DNS
599 or host name or NetBIOS name. This uses the name switch in the
600 smb.conf to determine the order of name resolution.
601 *********************************************************/
603 static BOOL internal_resolve_name(const char *name, int name_type,
604 struct in_addr **return_iplist, int *return_count)
606 pstring name_resolve_list;
609 BOOL allones = (strcmp(name,"255.255.255.255") == 0);
610 BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
611 BOOL is_address = is_ipaddress(name);
612 *return_iplist = NULL;
615 if (allzeros || allones || is_address) {
616 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
617 if(*return_iplist == NULL) {
618 DEBUG(3,("internal_resolve_name: malloc fail !\n"));
622 /* if it's in the form of an IP address then get the lib to interpret it */
623 (*return_iplist)->s_addr = inet_addr(name);
625 (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
631 pstrcpy(name_resolve_list, lp_name_resolve_order());
632 ptr = name_resolve_list;
636 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
637 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
638 if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) {
641 } else if(strequal( tok, "lmhosts")) {
642 if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
645 } else if(strequal( tok, "wins")) {
646 /* don't resolve 1D via WINS */
647 if (name_type != 0x1D &&
648 resolve_wins(name, name_type, return_iplist, return_count)) {
651 } else if(strequal( tok, "bcast")) {
652 if (resolve_bcast(name, name_type, return_iplist, return_count)) {
656 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
660 if((*return_iplist) != NULL) {
661 free((char *)(*return_iplist));
662 *return_iplist = NULL;
667 /********************************************************
668 Internal interface to resolve a name into one IP address.
669 Use this function if the string is either an IP address, DNS
670 or host name or NetBIOS name. This uses the name switch in the
671 smb.conf to determine the order of name resolution.
672 *********************************************************/
674 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
676 struct in_addr *ip_list = NULL;
679 if(internal_resolve_name(name, name_type, &ip_list, &count)) {
680 *return_ip = ip_list[0];
681 free((char *)ip_list);
685 free((char *)ip_list);
689 /********************************************************
690 Find the IP address of the master browser or DMB for a workgroup.
691 *********************************************************/
693 BOOL find_master_ip(char *group, struct in_addr *master_ip)
695 struct in_addr *ip_list = NULL;
698 if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
699 *master_ip = ip_list[0];
700 free((char *)ip_list);
703 if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
704 *master_ip = ip_list[0];
705 free((char *)ip_list);
710 free((char *)ip_list);
715 /********************************************************
716 Lookup a PDC name given a Domain name and IP address.
717 *********************************************************/
718 BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pdc_ip, char *ret_name)
721 int retry_time = 2000;
723 struct packet_struct p;
724 struct dgram_packet *dgram = &p.packet.dgram;
728 struct sockaddr_in sock_name;
729 int sock_len = sizeof(sock_name);
730 const char *mailslot = "\\MAILSLOT\\NET\\NETLOGON";
734 int dgm_id = generate_trn_id();
735 int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
740 /* Find out the transient UDP port we have been allocated. */
741 if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
742 DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
749 * Create the request data.
752 memset(buffer,'\0',sizeof(buffer));
754 SSVAL(bufp,0,QUERYFORPDC);
756 fstrcpy(bufp,srcname);
757 bufp += (strlen(bufp) + 1);
758 slprintf(bufp, sizeof(fstring), "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
759 mailslot_name = bufp;
760 bufp += (strlen(bufp) + 1);
761 bufp = ALIGN2(bufp, buffer);
762 bufp += dos_PutUniCode(bufp, srcname, sizeof(buffer) - (bufp - buffer) - 1, True);
764 SSVAL(bufp,4,0xFFFF);
765 SSVAL(bufp,6,0xFFFF);
767 len = PTR_DIFF(bufp,buffer);
769 memset((char *)&p,'\0',sizeof(p));
771 /* DIRECT GROUP or UNIQUE datagram. */
772 dgram->header.msg_type = 0x10;
773 dgram->header.flags.node_type = M_NODE;
774 dgram->header.flags.first = True;
775 dgram->header.flags.more = False;
776 dgram->header.dgm_id = dgm_id;
777 dgram->header.source_ip = *iface_ip(*pdc_ip);
778 dgram->header.source_port = ntohs(sock_name.sin_port);
779 dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
780 dgram->header.packet_offset = 0;
782 make_nmb_name(&dgram->source_name,srcname,0);
783 make_nmb_name(&dgram->dest_name,domain,0x1B);
785 ptr = &dgram->data[0];
787 /* Setup the smb part. */
788 ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
790 set_message(ptr,17,17 + len,True);
793 CVAL(ptr,smb_com) = SMBtrans;
794 SSVAL(ptr,smb_vwv1,len);
795 SSVAL(ptr,smb_vwv11,len);
796 SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
797 SSVAL(ptr,smb_vwv13,3);
798 SSVAL(ptr,smb_vwv14,1);
799 SSVAL(ptr,smb_vwv15,1);
800 SSVAL(ptr,smb_vwv16,2);
802 pstrcpy(p2,mailslot);
803 p2 = skip_string(p2,1);
805 memcpy(p2,buffer,len);
808 dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
813 p.timestamp = time(NULL);
814 p.packet_type = DGRAM_PACKET;
818 if (!send_packet(&p)) {
819 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
827 struct timeval tval2;
828 struct packet_struct *p_ret;
830 GetTimeOfDay(&tval2);
831 if (TvalDiff(&tval,&tval2) > retry_time) {
834 if (!send_packet(&p)) {
835 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
843 if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
844 struct dgram_packet *dgram2 = &p_ret->packet.dgram;
848 buf = &dgram2->data[0];
851 if (CVAL(buf,smb_com) != SMBtrans) {
852 DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)
853 CVAL(buf,smb_com), (unsigned int)SMBtrans ));
858 len = SVAL(buf,smb_vwv11);
859 buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
862 DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
867 DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
868 nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
869 inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len));
871 if(SVAL(buf2,0) != QUERYFORPDC_R) {
872 DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
873 (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
879 /* Note this is safe as it is a bounded strcpy. */
880 fstrcpy(ret_name, buf2);
881 ret_name[sizeof(fstring)-1] = '\0';
893 /********************************************************
894 Get the IP address list of the PDC/BDC's of a Domain.
895 *********************************************************/
896 BOOL get_dc_list(char *group, struct in_addr **ip_list, int *count)
898 return internal_resolve_name(group, 0x1C, ip_list, count);