First shot at actually *doing* WINS failover.
[Samba.git] / source3 / libsmb / namequery.c
blob6e0bf3375e285d67bbbcfe3a0512f7ac2005b034
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 name query routines
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.
23 #include "includes.h"
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)
35 static int trn_id;
37 if (trn_id == 0) {
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;
59 p += 1;
60 while (numnames--) {
61 char qname[17];
62 int type;
63 fstring flags;
64 int i;
65 *flags = 0;
66 StrnCpy(qname,p,15);
67 type = CVAL(p,15);
68 p += 16;
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));
94 p+=2;
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 *))
109 BOOL found=False;
110 int retries = 2;
111 int retry_time = 5000;
112 struct timeval tval;
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;
138 p.ip = to_ip;
139 p.port = NMB_PORT;
140 p.fd = fd;
141 p.timestamp = time(NULL);
142 p.packet_type = NMB_PACKET;
144 GetTimeOfDay(&tval);
146 if (!send_packet(&p))
147 return(False);
149 retries--;
151 while (1) {
152 struct timeval tval2;
153 GetTimeOfDay(&tval2);
154 if (TvalDiff(&tval,&tval2) > retry_time) {
155 if (!retries)
156 break;
157 if (!found && !send_packet(&p))
158 return False;
159 GetTimeOfDay(&tval);
160 retries--;
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
174 moment */
175 free_packet(p2);
176 continue;
179 if(fn_interpret_node_status)
180 (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname);
181 free_packet(p2);
182 return(True);
186 if(verbose)
187 DEBUG(0,("No status response (this is not unusual)\n"));
189 return(False);
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)
214 BOOL found=False;
215 int i, retries = 3;
216 int retry_time = bcast?250:2000;
217 struct timeval tval;
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));
224 (*count) = 0;
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;
245 p.ip = to_ip;
246 p.port = NMB_PORT;
247 p.fd = fd;
248 p.timestamp = time(NULL);
249 p.packet_type = NMB_PACKET;
251 GetTimeOfDay(&tval);
253 if (!send_packet(&p))
254 return NULL;
256 retries--;
258 while (1)
260 struct timeval tval2;
261 GetTimeOfDay(&tval2);
262 if (TvalDiff(&tval,&tval2) > retry_time) {
263 if (!retries)
264 break;
265 if (!found && !send_packet(&p))
266 return NULL;
267 GetTimeOfDay(&tval);
268 retries--;
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 we get a Negative Name Query Response from a WINS
276 * server, we should report it and give up.
278 if( 0 == nmb2->header.opcode /* A query response */
279 && !(bcast) /* from a WINS server */
280 && nmb2->header.rcode /* Error returned */
283 if( DEBUGLVL( 3 ) ) {
284 /* Only executed if DEBUGLEVEL >= 3 */
285 dbgtext( "Negative name query response, rcode 0x%02x: ",
286 nmb2->header.rcode );
287 switch( nmb2->header.rcode ) {
288 case 0x01:
289 dbgtext( "Request was invalidly formatted.\n" );
290 break;
291 case 0x02:
292 dbgtext( "Problem with NBNS, cannot process name.\n");
293 break;
294 case 0x03:
295 dbgtext( "The name requested does not exist.\n" );
296 break;
297 case 0x04:
298 dbgtext( "Unsupported request error.\n" );
299 break;
300 case 0x05:
301 dbgtext( "Query refused error.\n" );
302 break;
303 default:
304 dbgtext( "Unrecognized error code.\n" );
305 break;
308 free_packet(p2);
309 return( NULL );
312 if (nmb2->header.opcode != 0 ||
313 nmb2->header.nm_flags.bcast ||
314 nmb2->header.rcode ||
315 !nmb2->header.ancount) {
317 * XXXX what do we do with this? Could be a
318 * redirect, but we'll discard it for the
319 * moment. */
320 free_packet(p2);
321 continue;
324 ip_list = (struct in_addr *)Realloc( ip_list,
325 sizeof( ip_list[0] )
326 * ( (*count) + nmb2->answers->rdlength/6 ) );
327 if (ip_list) {
328 DEBUG(2,("Got a positive name query response from %s ( ",
329 inet_ntoa(p2->ip)));
330 for (i=0;i<nmb2->answers->rdlength/6;i++) {
331 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
332 DEBUGADD(2,("%s ",inet_ntoa(ip_list[(*count)])));
333 (*count)++;
335 DEBUGADD(2,(")\n"));
338 found=True;
339 retries=0;
340 free_packet(p2);
342 * If we're doing a unicast lookup we only
343 * expect one reply. Don't wait the full 2
344 * seconds if we got one. JRA.
346 if(!bcast && found)
347 break;
351 /* Reach here if we've timed out waiting for replies.. */
352 if( !bcast && !found )
354 /* Timed out wating for WINS server to respond. Mark it dead. */
355 wins_srv_died( to_ip );
358 return ip_list;
361 /********************************************************
362 Start parsing the lmhosts file.
363 *********************************************************/
365 FILE *startlmhosts(char *fname)
367 FILE *fp = sys_fopen(fname,"r");
368 if (!fp) {
369 DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
370 fname, strerror(errno)));
371 return NULL;
373 return fp;
376 /********************************************************
377 Parse the next line in the lmhosts file.
378 *********************************************************/
380 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
382 pstring line;
384 while(!feof(fp) && !ferror(fp)) {
385 pstring ip,flags,extra;
386 char *ptr;
387 int count = 0;
389 *name_type = -1;
391 if (!fgets_slash(line,sizeof(pstring),fp))
392 continue;
394 if (*line == '#')
395 continue;
397 pstrcpy(ip,"");
398 pstrcpy(name,"");
399 pstrcpy(flags,"");
401 ptr = line;
403 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
404 ++count;
405 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
406 ++count;
407 if (next_token(&ptr,flags,NULL, sizeof(flags)))
408 ++count;
409 if (next_token(&ptr,extra,NULL, sizeof(extra)))
410 ++count;
412 if (count <= 0)
413 continue;
415 if (count > 0 && count < 2)
417 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
418 continue;
421 if (count >= 4)
423 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
424 continue;
427 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
429 if (strchr(flags,'G') || strchr(flags,'S'))
431 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
432 continue;
435 *ipaddr = *interpret_addr2(ip);
437 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
438 then only add that name type. */
439 if((ptr = strchr(name, '#')) != NULL)
441 char *endptr;
443 ptr++;
444 *name_type = (int)strtol(ptr, &endptr, 16);
446 if(!*ptr || (endptr == ptr))
448 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
449 continue;
452 *(--ptr) = '\0'; /* Truncate at the '#' */
455 return True;
458 return False;
461 /********************************************************
462 Finish parsing the lmhosts file.
463 *********************************************************/
465 void endlmhosts(FILE *fp)
467 fclose(fp);
470 /********************************************************
471 Resolve via "bcast" method.
472 *********************************************************/
474 static BOOL resolve_bcast(const char *name, int name_type,
475 struct in_addr **return_ip_list, int *return_count)
477 int sock, i;
478 int num_interfaces = iface_count();
480 *return_ip_list = NULL;
481 *return_count = 0;
484 * "bcast" means do a broadcast lookup on all the local interfaces.
487 DEBUG(3,("resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
489 sock = open_socket_in( SOCK_DGRAM, 0, 3,
490 interpret_addr(lp_socket_address()), True );
492 if (sock == -1) return False;
494 set_socket_options(sock,"SO_BROADCAST");
496 * Lookup the name on all the interfaces, return on
497 * the first successful match.
499 for( i = num_interfaces-1; i >= 0; i--) {
500 struct in_addr sendto_ip;
501 /* Done this way to fix compiler error on IRIX 5.x */
502 sendto_ip = *iface_bcast(*iface_n_ip(i));
503 *return_ip_list = name_query(sock, name, name_type, True,
504 True, sendto_ip, return_count);
505 if(*return_ip_list != NULL) {
506 close(sock);
507 return True;
511 close(sock);
512 return False;
515 /********************************************************
516 Resolve via "wins" method.
517 *********************************************************/
519 static BOOL resolve_wins(const char *name, int name_type,
520 struct in_addr **return_iplist, int *return_count)
522 int sock;
523 struct in_addr wins_ip;
524 BOOL wins_ismyip;
526 *return_iplist = NULL;
527 *return_count = 0;
530 * "wins" means do a unicast lookup to the WINS server.
531 * Ignore if there is no WINS server specified or if the
532 * WINS server is one of our interfaces (if we're being
533 * called from within nmbd - we can't do this call as we
534 * would then block).
537 DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
539 if( wins_srv_count() < 1 ) {
540 DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
541 return False;
544 wins_ip = wins_srv_ip();
545 wins_ismyip = ismyip(wins_ip);
547 DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) );
548 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
549 sock = open_socket_in( SOCK_DGRAM, 0, 3,
550 interpret_addr(lp_socket_address()),
551 True );
552 if (sock != -1) {
553 *return_iplist = name_query( sock, name,
554 name_type, False,
555 True, wins_ip,
556 return_count);
557 if(*return_iplist != NULL) {
558 close(sock);
559 return True;
561 close(sock);
565 return False;
568 /********************************************************
569 Resolve via "lmhosts" method.
570 *********************************************************/
572 static BOOL resolve_lmhosts(const char *name, int name_type,
573 struct in_addr **return_iplist, int *return_count)
576 * "lmhosts" means parse the local lmhosts file.
579 FILE *fp;
580 pstring lmhost_name;
581 int name_type2;
582 struct in_addr return_ip;
584 *return_iplist = NULL;
585 *return_count = 0;
587 DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
589 fp = startlmhosts( LMHOSTSFILE );
590 if(fp) {
591 while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
592 if (strequal(name, lmhost_name) &&
593 ((name_type2 == -1) || (name_type == name_type2))
595 endlmhosts(fp);
596 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
597 if(*return_iplist == NULL) {
598 DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
599 return False;
601 **return_iplist = return_ip;
602 *return_count = 1;
603 return True;
606 endlmhosts(fp);
608 return False;
612 /********************************************************
613 Resolve via "hosts" method.
614 *********************************************************/
616 static BOOL resolve_hosts(const char *name,
617 struct in_addr **return_iplist, int *return_count)
620 * "host" means do a localhost, or dns lookup.
622 struct hostent *hp;
624 *return_iplist = NULL;
625 *return_count = 0;
627 DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
629 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
630 struct in_addr return_ip;
631 putip((char *)&return_ip,(char *)hp->h_addr);
632 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
633 if(*return_iplist == NULL) {
634 DEBUG(3,("resolve_hosts: malloc fail !\n"));
635 return False;
637 **return_iplist = return_ip;
638 *return_count = 1;
639 return True;
641 return False;
644 /********************************************************
645 Resolve a name into an IP address. Use this function if
646 the string is either an IP address, DNS or host name
647 or NetBIOS name. This uses the name switch in the
648 smb.conf to determine the order of name resolution.
649 *********************************************************/
650 BOOL is_ip_address(const char *name)
652 int i;
653 for (i=0; name[i]; i++)
654 if (!(isdigit((int)name[i]) || name[i] == '.'))
655 return False;
657 return True;
661 /********************************************************
662 Internal interface to resolve a name into an IP address.
663 Use this function if the string is either an IP address, DNS
664 or host name or NetBIOS name. This uses the name switch in the
665 smb.conf to determine the order of name resolution.
666 *********************************************************/
668 static BOOL internal_resolve_name(const char *name, int name_type,
669 struct in_addr **return_iplist, int *return_count)
671 pstring name_resolve_list;
672 fstring tok;
673 char *ptr;
674 BOOL allones = (strcmp(name,"255.255.255.255") == 0);
675 BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
676 BOOL is_address = is_ipaddress(name);
677 *return_iplist = NULL;
678 *return_count = 0;
680 if (allzeros || allones || is_address) {
681 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
682 if(*return_iplist == NULL) {
683 DEBUG(3,("internal_resolve_name: malloc fail !\n"));
684 return False;
686 if(is_address) {
687 /* if it's in the form of an IP address then get the lib to interpret it */
688 (*return_iplist)->s_addr = inet_addr(name);
689 } else {
690 (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
691 *return_count = 1;
693 return True;
696 pstrcpy(name_resolve_list, lp_name_resolve_order());
697 ptr = name_resolve_list;
698 if (!ptr || !*ptr)
699 ptr = "host";
701 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
702 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
703 if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) {
704 return True;
706 } else if(strequal( tok, "lmhosts")) {
707 if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
708 return True;
710 } else if(strequal( tok, "wins")) {
711 /* don't resolve 1D via WINS */
712 if (name_type != 0x1D &&
713 resolve_wins(name, name_type, return_iplist, return_count)) {
714 return True;
716 } else if(strequal( tok, "bcast")) {
717 if (resolve_bcast(name, name_type, return_iplist, return_count)) {
718 return True;
720 } else {
721 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
725 if((*return_iplist) != NULL) {
726 free((char *)(*return_iplist));
727 *return_iplist = NULL;
729 return False;
732 /********************************************************
733 Internal interface to resolve a name into one IP address.
734 Use this function if the string is either an IP address, DNS
735 or host name or NetBIOS name. This uses the name switch in the
736 smb.conf to determine the order of name resolution.
737 *********************************************************/
739 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
741 struct in_addr *ip_list = NULL;
742 int count = 0;
744 if(internal_resolve_name(name, name_type, &ip_list, &count)) {
745 *return_ip = ip_list[0];
746 free((char *)ip_list);
747 return True;
749 if(ip_list != NULL)
750 free((char *)ip_list);
751 return False;
755 /********************************************************
756 resolve a name of format \\server_name or \\ipaddress
757 into a name. also, cut the \\ from the front for us.
758 *********************************************************/
760 BOOL resolve_srv_name(const char* srv_name, fstring dest_host,
761 struct in_addr *ip)
763 BOOL ret;
764 const char *sv_name = srv_name;
766 DEBUG(10,("resolve_srv_name: %s\n", srv_name));
768 if (srv_name == NULL || strequal("\\\\.", srv_name))
770 extern pstring global_myname;
771 fstrcpy(dest_host, global_myname);
772 ip = interpret_addr2("127.0.0.1");
773 return True;
776 if (strnequal("\\\\", srv_name, 2))
778 sv_name = &srv_name[2];
781 fstrcpy(dest_host, sv_name);
782 /* treat the '*' name specially - it is a magic name for the PDC */
783 if (strcmp(dest_host,"*") == 0) {
784 extern pstring global_myname;
785 ret = resolve_name(lp_workgroup(), ip, 0x1B);
786 lookup_pdc_name(global_myname, lp_workgroup(), ip, dest_host);
787 } else {
788 ret = resolve_name(dest_host, ip, 0x20);
791 if (is_ip_address(dest_host))
793 fstrcpy(dest_host, "*SMBSERVER");
796 return ret;
800 /********************************************************
801 Find the IP address of the master browser or DMB for a workgroup.
802 *********************************************************/
804 BOOL find_master_ip(char *group, struct in_addr *master_ip)
806 struct in_addr *ip_list = NULL;
807 int count = 0;
809 if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
810 *master_ip = ip_list[0];
811 free((char *)ip_list);
812 return True;
814 if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
815 *master_ip = ip_list[0];
816 free((char *)ip_list);
817 return True;
820 if(ip_list != NULL)
821 free((char *)ip_list);
822 return False;
826 /********************************************************
827 Lookup a PDC name given a Domain name and IP address.
828 *********************************************************/
829 BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pdc_ip, char *ret_name)
831 int retries = 3;
832 int retry_time = 2000;
833 struct timeval tval;
834 struct packet_struct p;
835 struct dgram_packet *dgram = &p.packet.dgram;
836 char *ptr,*p2;
837 char tmp[4];
838 int len;
839 struct sockaddr_in sock_name;
840 int sock_len = sizeof(sock_name);
841 const char *mailslot = "\\MAILSLOT\\NET\\NETLOGON";
842 char *mailslot_name;
843 char buffer[1024];
844 char *bufp;
845 int dgm_id = generate_trn_id();
846 int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
848 if(sock == -1)
849 return False;
851 /* Find out the transient UDP port we have been allocated. */
852 if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
853 DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
854 strerror(errno)));
855 close(sock);
856 return False;
860 * Create the request data.
863 memset(buffer,'\0',sizeof(buffer));
864 bufp = buffer;
865 SSVAL(bufp,0,QUERYFORPDC);
866 bufp += 2;
867 fstrcpy(bufp,srcname);
868 bufp += (strlen(bufp) + 1);
869 slprintf(bufp, sizeof(fstring), "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
870 mailslot_name = bufp;
871 bufp += (strlen(bufp) + 1);
872 bufp = ALIGN2(bufp, buffer);
873 bufp += dos_PutUniCode(bufp, srcname, sizeof(buffer) - (bufp - buffer) - 1, True);
874 SIVAL(bufp,0,1);
875 SSVAL(bufp,4,0xFFFF);
876 SSVAL(bufp,6,0xFFFF);
877 bufp += 8;
878 len = PTR_DIFF(bufp,buffer);
880 memset((char *)&p,'\0',sizeof(p));
882 /* DIRECT GROUP or UNIQUE datagram. */
883 dgram->header.msg_type = 0x10;
884 dgram->header.flags.node_type = M_NODE;
885 dgram->header.flags.first = True;
886 dgram->header.flags.more = False;
887 dgram->header.dgm_id = dgm_id;
888 dgram->header.source_ip = *iface_ip(*pdc_ip);
889 dgram->header.source_port = ntohs(sock_name.sin_port);
890 dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
891 dgram->header.packet_offset = 0;
893 make_nmb_name(&dgram->source_name,srcname,0);
894 make_nmb_name(&dgram->dest_name,domain,0x1B);
896 ptr = &dgram->data[0];
898 /* Setup the smb part. */
899 ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
900 memcpy(tmp,ptr,4);
901 set_message(ptr,17,17 + len,True);
902 memcpy(ptr,tmp,4);
904 CVAL(ptr,smb_com) = SMBtrans;
905 SSVAL(ptr,smb_vwv1,len);
906 SSVAL(ptr,smb_vwv11,len);
907 SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
908 SSVAL(ptr,smb_vwv13,3);
909 SSVAL(ptr,smb_vwv14,1);
910 SSVAL(ptr,smb_vwv15,1);
911 SSVAL(ptr,smb_vwv16,2);
912 p2 = smb_buf(ptr);
913 pstrcpy(p2,mailslot);
914 p2 = skip_string(p2,1);
916 memcpy(p2,buffer,len);
917 p2 += len;
919 dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
921 p.ip = *pdc_ip;
922 p.port = DGRAM_PORT;
923 p.fd = sock;
924 p.timestamp = time(NULL);
925 p.packet_type = DGRAM_PACKET;
927 GetTimeOfDay(&tval);
929 if (!send_packet(&p)) {
930 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
931 close(sock);
932 return False;
935 retries--;
937 while (1) {
938 struct timeval tval2;
939 struct packet_struct *p_ret;
941 GetTimeOfDay(&tval2);
942 if (TvalDiff(&tval,&tval2) > retry_time) {
943 if (!retries)
944 break;
945 if (!send_packet(&p)) {
946 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
947 close(sock);
948 return False;
950 GetTimeOfDay(&tval);
951 retries--;
954 if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
955 struct dgram_packet *dgram2 = &p_ret->packet.dgram;
956 char *buf;
957 char *buf2;
959 buf = &dgram2->data[0];
960 buf -= 4;
962 if (CVAL(buf,smb_com) != SMBtrans) {
963 DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)
964 CVAL(buf,smb_com), (unsigned int)SMBtrans ));
965 free_packet(p_ret);
966 continue;
969 len = SVAL(buf,smb_vwv11);
970 buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
972 if (len <= 0) {
973 DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
974 free_packet(p_ret);
975 continue;
978 DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
979 nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
980 inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len));
982 if(SVAL(buf2,0) != QUERYFORPDC_R) {
983 DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
984 (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
985 free_packet(p_ret);
986 continue;
989 buf2 += 2;
990 /* Note this is safe as it is a bounded strcpy. */
991 fstrcpy(ret_name, buf2);
992 ret_name[sizeof(fstring)-1] = '\0';
993 close(sock);
994 free_packet(p_ret);
995 return True;
999 close(sock);
1000 return False;
1004 /********************************************************
1005 Get the IP address list of the PDC/BDC's of a Domain.
1006 *********************************************************/
1007 BOOL get_dc_list(char *group, struct in_addr **ip_list, int *count)
1009 return internal_resolve_name(group, 0x1C, ip_list, count);