dnscrypto-proxy: Support files updated.
[tomato.git] / release / src / router / samba / source / libsmb / namequery.c
blob8d2bd2c6b4768d0758045763848d836ee786175b
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 Interpret a node status response.
32 ****************************************************************************/
34 static void _interpret_node_status(char *p, char *master,char *rname)
36 int numnames = CVAL(p,0);
37 DEBUG(1,("received %d names\n",numnames));
39 if (rname) *rname = 0;
40 if (master) *master = 0;
42 p += 1;
43 while (numnames--) {
44 char qname[17];
45 int type;
46 fstring flags;
47 int i;
48 *flags = 0;
49 StrnCpy(qname,p,15);
50 type = CVAL(p,15);
51 p += 16;
53 fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
54 if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
55 if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
56 if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
57 if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
58 if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
59 if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
60 if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
61 if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
63 if (master && !*master && type == 0x1d) {
64 StrnCpy(master,qname,15);
65 trim_string(master,NULL," ");
68 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
69 StrnCpy(rname,qname,15);
70 trim_string(rname,NULL," ");
73 for (i = strlen( qname) ; --i >= 0 ; ) {
74 if (!isprint((int)qname[i])) qname[i] = '.';
76 DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
77 p+=2;
80 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
81 IVAL(p,20),IVAL(p,24)));
84 /****************************************************************************
85 Internal function handling a netbios name status query on a host.
86 **************************************************************************/
88 static BOOL internal_name_status(int fd,char *name,int name_type,BOOL recurse,
89 struct in_addr to_ip,char *master,char *rname, BOOL verbose,
90 void (*fn_interpret_node_status)(char *, char *,char *),
91 void (*fn)(struct packet_struct *))
93 BOOL found=False;
94 int retries = 2;
95 int retry_time = 5000;
96 struct timeval tval;
97 struct packet_struct p;
98 struct packet_struct *p2;
99 struct nmb_packet *nmb = &p.packet.nmb;
100 static int name_trn_id = 0;
102 memset((char *)&p,'\0',sizeof(p));
104 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
105 ((unsigned)getpid()%(unsigned)100);
106 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
108 nmb->header.name_trn_id = name_trn_id;
109 nmb->header.opcode = 0;
110 nmb->header.response = False;
111 nmb->header.nm_flags.bcast = False;
112 nmb->header.nm_flags.recursion_available = False;
113 nmb->header.nm_flags.recursion_desired = False;
114 nmb->header.nm_flags.trunc = False;
115 nmb->header.nm_flags.authoritative = False;
116 nmb->header.rcode = 0;
117 nmb->header.qdcount = 1;
118 nmb->header.ancount = 0;
119 nmb->header.nscount = 0;
120 nmb->header.arcount = 0;
122 make_nmb_name(&nmb->question.question_name,name,name_type);
124 nmb->question.question_type = 0x21;
125 nmb->question.question_class = 0x1;
127 p.ip = to_ip;
128 p.port = NMB_PORT;
129 p.fd = fd;
130 p.timestamp = time(NULL);
131 p.packet_type = NMB_PACKET;
133 GetTimeOfDay(&tval);
135 if (!send_packet(&p))
136 return(False);
138 retries--;
140 while (1) {
141 struct timeval tval2;
142 GetTimeOfDay(&tval2);
143 if (TvalDiff(&tval,&tval2) > retry_time) {
144 if (!retries)
145 break;
146 if (!found && !send_packet(&p))
147 return False;
148 GetTimeOfDay(&tval);
149 retries--;
152 if ((p2=receive_packet(fd,NMB_PACKET,90))) {
153 struct nmb_packet *nmb2 = &p2->packet.nmb;
154 debug_nmb_packet(p2);
156 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
157 !nmb2->header.response) {
158 /* its not for us - maybe deal with it later */
159 if (fn)
160 fn(p2);
161 else
162 free_packet(p2);
163 continue;
166 if (nmb2->header.opcode != 0 ||
167 nmb2->header.nm_flags.bcast ||
168 nmb2->header.rcode ||
169 !nmb2->header.ancount ||
170 nmb2->answers->rr_type != 0x21) {
171 /* XXXX what do we do with this? could be a redirect, but
172 we'll discard it for the moment */
173 free_packet(p2);
174 continue;
177 if(fn_interpret_node_status)
178 (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname);
179 free_packet(p2);
180 return(True);
184 if(verbose)
185 DEBUG(0,("No status response (this is not unusual)\n"));
187 return(False);
190 /****************************************************************************
191 Do a netbios name status query on a host.
192 The "master" parameter is a hack used for finding workgroups.
193 **************************************************************************/
195 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
196 struct in_addr to_ip,char *master,char *rname,
197 void (*fn)(struct packet_struct *))
199 return internal_name_status(fd,name,name_type,recurse,
200 to_ip,master,rname,True,
201 _interpret_node_status, fn);
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, BOOL bcast,BOOL recurse,
211 struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
213 BOOL found=False;
214 int i, retries = 3;
215 int retry_time = bcast?250:2000;
216 struct timeval tval;
217 struct packet_struct p;
218 struct packet_struct *p2;
219 struct nmb_packet *nmb = &p.packet.nmb;
220 static int name_trn_id = 0;
221 struct in_addr *ip_list = NULL;
223 memset((char *)&p,'\0',sizeof(p));
224 (*count) = 0;
226 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
227 ((unsigned)getpid()%(unsigned)100);
228 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
230 nmb->header.name_trn_id = name_trn_id;
231 nmb->header.opcode = 0;
232 nmb->header.response = False;
233 nmb->header.nm_flags.bcast = bcast;
234 nmb->header.nm_flags.recursion_available = False;
235 nmb->header.nm_flags.recursion_desired = recurse;
236 nmb->header.nm_flags.trunc = False;
237 nmb->header.nm_flags.authoritative = False;
238 nmb->header.rcode = 0;
239 nmb->header.qdcount = 1;
240 nmb->header.ancount = 0;
241 nmb->header.nscount = 0;
242 nmb->header.arcount = 0;
244 make_nmb_name(&nmb->question.question_name,name,name_type);
246 nmb->question.question_type = 0x20;
247 nmb->question.question_class = 0x1;
249 p.ip = to_ip;
250 p.port = NMB_PORT;
251 p.fd = fd;
252 p.timestamp = time(NULL);
253 p.packet_type = NMB_PACKET;
255 GetTimeOfDay(&tval);
257 if (!send_packet(&p))
258 return NULL;
260 retries--;
262 while (1)
264 struct timeval tval2;
265 GetTimeOfDay(&tval2);
266 if (TvalDiff(&tval,&tval2) > retry_time)
268 if (!retries)
269 break;
270 if (!found && !send_packet(&p))
271 return NULL;
272 GetTimeOfDay(&tval);
273 retries--;
276 if ((p2=receive_packet(fd,NMB_PACKET,90)))
278 struct nmb_packet *nmb2 = &p2->packet.nmb;
279 debug_nmb_packet(p2);
281 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
282 !nmb2->header.response)
285 * Its not for us - maybe deal with it later
286 * (put it on the queue?).
288 if (fn)
289 fn(p2);
290 else
291 free_packet(p2);
292 continue;
295 if (nmb2->header.opcode != 0 ||
296 nmb2->header.nm_flags.bcast ||
297 nmb2->header.rcode ||
298 !nmb2->header.ancount)
301 * XXXX what do we do with this? Could be a redirect, but
302 * we'll discard it for the moment.
304 free_packet(p2);
305 continue;
308 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
309 ((*count)+nmb2->answers->rdlength/6));
310 if (ip_list)
312 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
313 inet_ntoa(p2->ip)));
314 for (i=0;i<nmb2->answers->rdlength/6;i++)
316 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
317 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
318 (*count)++;
320 DEBUG(fn?3:2,(")\n"));
323 found=True;
324 retries=0;
325 free_packet(p2);
326 if (fn)
327 break;
330 * If we're doing a unicast lookup we only
331 * expect one reply. Don't wait the full 2
332 * seconds if we got one. JRA.
334 if(!bcast && found)
335 break;
339 return ip_list;
342 /********************************************************
343 Start parsing the lmhosts file.
344 *********************************************************/
346 FILE *startlmhosts(char *fname)
348 FILE *fp = sys_fopen(fname,"r");
349 if (!fp) {
350 DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
351 fname, strerror(errno)));
352 return NULL;
354 return fp;
357 /********************************************************
358 Parse the next line in the lmhosts file.
359 *********************************************************/
361 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
363 pstring line;
365 while(!feof(fp) && !ferror(fp)) {
366 pstring ip,flags,extra;
367 char *ptr;
368 int count = 0;
370 *name_type = -1;
372 if (!fgets_slash(line,sizeof(pstring),fp))
373 continue;
375 if (*line == '#')
376 continue;
378 pstrcpy(ip,"");
379 pstrcpy(name,"");
380 pstrcpy(flags,"");
382 ptr = line;
384 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
385 ++count;
386 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
387 ++count;
388 if (next_token(&ptr,flags,NULL, sizeof(flags)))
389 ++count;
390 if (next_token(&ptr,extra,NULL, sizeof(extra)))
391 ++count;
393 if (count <= 0)
394 continue;
396 if (count > 0 && count < 2)
398 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
399 continue;
402 if (count >= 4)
404 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
405 continue;
408 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
410 if (strchr(flags,'G') || strchr(flags,'S'))
412 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
413 continue;
416 *ipaddr = *interpret_addr2(ip);
418 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
419 then only add that name type. */
420 if((ptr = strchr(name, '#')) != NULL)
422 char *endptr;
424 ptr++;
425 *name_type = (int)strtol(ptr, &endptr, 16);
427 if(!*ptr || (endptr == ptr))
429 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
430 continue;
433 *(--ptr) = '\0'; /* Truncate at the '#' */
436 return True;
439 return False;
442 /********************************************************
443 Finish parsing the lmhosts file.
444 *********************************************************/
446 void endlmhosts(FILE *fp)
448 fclose(fp);
451 /********************************************************
452 Resolve via "bcast" method.
453 *********************************************************/
455 static BOOL resolve_bcast(const char *name, int name_type,
456 struct in_addr **return_ip_list, int *return_count)
458 int sock, i;
459 int num_interfaces = iface_count();
461 *return_ip_list = NULL;
462 *return_count = 0;
465 * "bcast" means do a broadcast lookup on all the local interfaces.
468 DEBUG(3,("resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
470 sock = open_socket_in( SOCK_DGRAM, 0, 3,
471 interpret_addr(lp_socket_address()), True );
473 if (sock == -1) return False;
475 set_socket_options(sock,"SO_BROADCAST");
477 * Lookup the name on all the interfaces, return on
478 * the first successful match.
480 for( i = num_interfaces-1; i >= 0; i--) {
481 struct in_addr sendto_ip;
482 /* Done this way to fix compiler error on IRIX 5.x */
483 sendto_ip = *iface_bcast(*iface_n_ip(i));
484 *return_ip_list = name_query(sock, name, name_type, True,
485 True, sendto_ip, return_count, NULL);
486 if(*return_ip_list != NULL) {
487 close(sock);
488 return True;
492 close(sock);
493 return False;
496 /********************************************************
497 Resolve via "wins" method.
498 *********************************************************/
500 static BOOL resolve_wins(const char *name, int name_type,
501 struct in_addr **return_iplist, int *return_count)
503 int sock;
504 struct in_addr wins_ip;
505 BOOL wins_ismyip;
507 *return_iplist = NULL;
508 *return_count = 0;
511 * "wins" means do a unicast lookup to the WINS server.
512 * Ignore if there is no WINS server specified or if the
513 * WINS server is one of our interfaces (if we're being
514 * called from within nmbd - we can't do this call as we
515 * would then block).
518 DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
520 if(!*lp_wins_server()) {
521 DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS server present.\n"));
522 return False;
525 wins_ip = *interpret_addr2(lp_wins_server());
526 wins_ismyip = ismyip(wins_ip);
528 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
529 sock = open_socket_in( SOCK_DGRAM, 0, 3,
530 interpret_addr(lp_socket_address()), True );
532 if (sock != -1) {
533 *return_iplist = name_query(sock, name, name_type, False,
534 True, wins_ip, return_count, NULL);
535 if(*return_iplist != NULL) {
536 close(sock);
537 return True;
539 close(sock);
543 return False;
546 /********************************************************
547 Resolve via "lmhosts" method.
548 *********************************************************/
550 static BOOL resolve_lmhosts(const char *name, int name_type,
551 struct in_addr **return_iplist, int *return_count)
554 * "lmhosts" means parse the local lmhosts file.
557 FILE *fp;
558 pstring lmhost_name;
559 int name_type2;
560 struct in_addr return_ip;
562 *return_iplist = NULL;
563 *return_count = 0;
565 DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
567 fp = startlmhosts( LMHOSTSFILE );
568 if(fp) {
569 while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
570 if (strequal(name, lmhost_name) &&
571 ((name_type2 == -1) || (name_type == name_type2))
573 endlmhosts(fp);
574 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
575 if(*return_iplist == NULL) {
576 DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
577 return False;
579 **return_iplist = return_ip;
580 *return_count = 1;
581 return True;
584 endlmhosts(fp);
586 return False;
590 /********************************************************
591 Resolve via "hosts" method.
592 *********************************************************/
594 static BOOL resolve_hosts(const char *name,
595 struct in_addr **return_iplist, int *return_count)
598 * "host" means do a localhost, or dns lookup.
600 struct hostent *hp;
602 *return_iplist = NULL;
603 *return_count = 0;
605 DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
607 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
608 struct in_addr return_ip;
609 putip((char *)&return_ip,(char *)hp->h_addr);
610 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
611 if(*return_iplist == NULL) {
612 DEBUG(3,("resolve_hosts: malloc fail !\n"));
613 return False;
615 **return_iplist = return_ip;
616 *return_count = 1;
617 return True;
619 return False;
622 /********************************************************
623 Internal interface to resolve a name into an IP address.
624 Use this function if the string is either an IP address, DNS
625 or host name or NetBIOS name. This uses the name switch in the
626 smb.conf to determine the order of name resolution.
627 *********************************************************/
629 static BOOL internal_resolve_name(const char *name, int name_type,
630 struct in_addr **return_iplist, int *return_count)
632 pstring name_resolve_list;
633 fstring tok;
634 char *ptr;
635 BOOL allones = (strcmp(name,"255.255.255.255") == 0);
636 BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
637 BOOL is_address = is_ipaddress(name);
638 *return_iplist = NULL;
639 *return_count = 0;
641 if (allzeros || allones || is_address) {
642 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
643 if(*return_iplist == NULL) {
644 DEBUG(3,("internal_resolve_name: malloc fail !\n"));
645 return False;
647 if(is_address) {
648 /* if it's in the form of an IP address then get the lib to interpret it */
649 (*return_iplist)->s_addr = inet_addr(name);
650 } else {
651 (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
652 *return_count = 1;
654 return True;
657 pstrcpy(name_resolve_list, lp_name_resolve_order());
658 ptr = name_resolve_list;
659 if (!ptr || !*ptr)
660 ptr = "host";
662 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
663 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
664 if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) {
665 return True;
667 } else if(strequal( tok, "lmhosts")) {
668 if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
669 return True;
671 } else if(strequal( tok, "wins")) {
672 /* don't resolve 1D via WINS */
673 if (name_type != 0x1D &&
674 resolve_wins(name, name_type, return_iplist, return_count)) {
675 return True;
677 } else if(strequal( tok, "bcast")) {
678 if (resolve_bcast(name, name_type, return_iplist, return_count)) {
679 return True;
681 } else {
682 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
686 if((*return_iplist) != NULL) {
687 free((char *)(*return_iplist));
688 *return_iplist = NULL;
690 return False;
693 /********************************************************
694 Internal interface to resolve a name into one IP address.
695 Use this function if the string is either an IP address, DNS
696 or host name or NetBIOS name. This uses the name switch in the
697 smb.conf to determine the order of name resolution.
698 *********************************************************/
700 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
702 struct in_addr *ip_list = NULL;
703 int count = 0;
705 if(internal_resolve_name(name, name_type, &ip_list, &count)) {
706 *return_ip = ip_list[0];
707 free((char *)ip_list);
708 return True;
710 if(ip_list != NULL)
711 free((char *)ip_list);
712 return False;
715 /********************************************************
716 Find the IP address of the master browser or DMB for a workgroup.
717 *********************************************************/
719 BOOL find_master_ip(char *group, struct in_addr *master_ip)
721 struct in_addr *ip_list = NULL;
722 int count = 0;
724 if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
725 *master_ip = ip_list[0];
726 free((char *)ip_list);
727 return True;
729 if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
730 *master_ip = ip_list[0];
731 free((char *)ip_list);
732 return True;
735 if(ip_list != NULL)
736 free((char *)ip_list);
737 return False;
740 /********************************************************
741 Internal function to extract the MACHINE<0x20> name.
742 *********************************************************/
744 static void _lookup_pdc_name(char *p, char *master,char *rname)
746 int numnames = CVAL(p,0);
748 *rname = '\0';
750 p += 1;
751 while (numnames--) {
752 int type = CVAL(p,15);
753 if(type == 0x20) {
754 StrnCpy(rname,p,15);
755 trim_string(rname,NULL," ");
756 return;
758 p += 18;
762 /********************************************************
763 Lookup a PDC name given a Domain name and IP address.
764 *********************************************************/
766 BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pdc_ip, char *ret_name)
768 #if !defined(I_HATE_WINDOWS_REPLY_CODE)
770 fstring pdc_name;
771 BOOL ret;
774 * Due to the fact win WinNT *sucks* we must do a node status
775 * query here... JRA.
778 int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
780 if(sock == -1)
781 return False;
783 *pdc_name = '\0';
785 ret = internal_name_status(sock,"*SMBSERVER",0x20,True,
786 *pdc_ip,NULL,pdc_name,False,
787 _lookup_pdc_name,NULL);
789 close(sock);
791 if(ret && *pdc_name) {
792 fstrcpy(ret_name, pdc_name);
793 return True;
796 return False;
798 #else /* defined(I_HATE_WINDOWS_REPLY_CODE) */
800 * Sigh. I *love* this code, it took me ages to get right and it's
801 * completely *USELESS* because NT 4.x refuses to send the mailslot
802 * reply back to the correct port (it always uses 138).
803 * I hate NT when it does these things... JRA.
806 int retries = 3;
807 int retry_time = 2000;
808 struct timeval tval;
809 struct packet_struct p;
810 struct dgram_packet *dgram = &p.packet.dgram;
811 char *ptr,*p2;
812 char tmp[4];
813 int len;
814 struct sockaddr_in sock_name;
815 int sock_len = sizeof(sock_name);
816 const char *mailslot = "\\MAILSLOT\\NET\\NETLOGON";
817 static int name_trn_id = 0;
818 char buffer[1024];
819 char *bufp;
820 int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
822 if(sock == -1)
823 return False;
825 /* Find out the transient UDP port we have been allocated. */
826 if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
827 DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
828 strerror(errno)));
829 close(sock);
830 return False;
834 * Create the request data.
837 memset(buffer,'\0',sizeof(buffer));
838 bufp = buffer;
839 SSVAL(bufp,0,QUERYFORPDC);
840 bufp += 2;
841 fstrcpy(bufp,srcname);
842 bufp += (strlen(bufp) + 1);
843 fstrcpy(bufp,"\\MAILSLOT\\NET\\GETDC411");
844 bufp += (strlen(bufp) + 1);
845 bufp = align2(bufp, buffer);
846 bufp += dos_PutUniCode(bufp, srcname, sizeof(buffer) - (bufp - buffer) - 1, True);
847 SIVAL(bufp,0,1);
848 SSVAL(bufp,4,0xFFFF);
849 SSVAL(bufp,6,0xFFFF);
850 bufp += 8;
851 len = PTR_DIFF(bufp,buffer);
853 if (!name_trn_id)
854 name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)getpid()%(unsigned)100);
855 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
857 memset((char *)&p,'\0',sizeof(p));
859 /* DIRECT GROUP or UNIQUE datagram. */
860 dgram->header.msg_type = 0x10;
861 dgram->header.flags.node_type = M_NODE;
862 dgram->header.flags.first = True;
863 dgram->header.flags.more = False;
864 dgram->header.dgm_id = name_trn_id;
865 dgram->header.source_ip = sock_name.sin_addr;
866 dgram->header.source_port = ntohs(sock_name.sin_port);
867 dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
868 dgram->header.packet_offset = 0;
870 make_nmb_name(&dgram->source_name,srcname,0);
871 make_nmb_name(&dgram->dest_name,domain,0x1B);
873 ptr = &dgram->data[0];
875 /* Setup the smb part. */
876 ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
877 memcpy(tmp,ptr,4);
878 set_message(ptr,17,17 + len,True);
879 memcpy(ptr,tmp,4);
881 CVAL(ptr,smb_com) = SMBtrans;
882 SSVAL(ptr,smb_vwv1,len);
883 SSVAL(ptr,smb_vwv11,len);
884 SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
885 SSVAL(ptr,smb_vwv13,3);
886 SSVAL(ptr,smb_vwv14,1);
887 SSVAL(ptr,smb_vwv15,1);
888 SSVAL(ptr,smb_vwv16,2);
889 p2 = smb_buf(ptr);
890 pstrcpy(p2,mailslot);
891 p2 = skip_string(p2,1);
893 memcpy(p2,buffer,len);
894 p2 += len;
896 dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
898 p.ip = *pdc_ip;
899 p.port = DGRAM_PORT;
900 p.fd = sock;
901 p.timestamp = time(NULL);
902 p.packet_type = DGRAM_PACKET;
904 GetTimeOfDay(&tval);
906 if (!send_packet(&p)) {
907 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
908 close(sock);
909 return False;
912 retries--;
914 while (1) {
915 struct timeval tval2;
916 struct packet_struct *p_ret;
918 GetTimeOfDay(&tval2);
919 if (TvalDiff(&tval,&tval2) > retry_time) {
920 if (!retries)
921 break;
922 if (!send_packet(&p)) {
923 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
924 close(sock);
925 return False;
927 GetTimeOfDay(&tval);
928 retries--;
931 if ((p_ret = receive_packet(sock,NMB_PACKET,90))) {
932 struct nmb_packet *nmb2 = &p_ret->packet.nmb;
933 struct dgram_packet *dgram2 = &p_ret->packet.dgram;
934 char *buf;
935 char *buf2;
937 debug_nmb_packet(p_ret);
939 if (memcmp(&p.ip, &p_ret->ip, sizeof(p.ip))) {
941 * Not for us.
943 DEBUG(0,("lookup_pdc_name: datagram return IP %s doesn't match\n", inet_ntoa(p_ret->ip) ));
944 free_packet(p_ret);
945 continue;
948 buf = &dgram2->data[0];
949 buf -= 4;
951 if (CVAL(buf,smb_com) != SMBtrans) {
952 DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)CVAL(buf,smb_com),
953 (unsigned int)SMBtrans ));
954 free_packet(p_ret);
955 continue;
958 len = SVAL(buf,smb_vwv11);
959 buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
961 if (len <= 0) {
962 DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
963 free_packet(p_ret);
964 continue;
967 DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
968 nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
969 inet_ntoa(p_ret->ip), smb_buf(buf),CVAL(buf2,0),len));
971 if(SVAL(buf,0) != QUERYFORPDC_R) {
972 DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
973 (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
974 free_packet(p_ret);
975 continue;
978 buf += 2;
979 /* Note this is safe as it is a bounded strcpy. */
980 fstrcpy(ret_name, buf);
981 ret_name[sizeof(fstring)-1] = '\0';
982 close(sock);
983 free_packet(p_ret);
984 return True;
988 close(sock);
989 return False;
990 #endif /* I_HATE_WINDOWS_REPLY_CODE */
993 /********************************************************
994 Get the IP address list of the PDC/BDC's of a Domain.
995 *********************************************************/
997 BOOL get_dc_list(char *group, struct in_addr **ip_list, int *count)
999 return internal_resolve_name(group, 0x1C, ip_list, count);