first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[nivanova/samba-autobuild/.git] / source3 / libsmb / namequery.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    name query routines
5    Copyright (C) Andrew Tridgell 1994-1998
6    
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.
11    
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.
16    
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.
20    
21 */
22
23 #include "includes.h"
24
25 extern pstring scope;
26 extern int DEBUGLEVEL;
27
28 /* nmbd.c sets this to True. */
29 BOOL global_in_nmbd = False;
30
31 /****************************************************************************
32  Interpret a node status response.
33 ****************************************************************************/
34
35 static void _interpret_node_status(char *p, char *master,char *rname)
36 {
37   int numnames = CVAL(p,0);
38   DEBUG(1,("received %d names\n",numnames));
39
40   if (rname) *rname = 0;
41   if (master) *master = 0;
42
43   p += 1;
44   while (numnames--) {
45     char qname[17];
46     int type;
47     fstring flags;
48     int i;
49     *flags = 0;
50     StrnCpy(qname,p,15);
51     type = CVAL(p,15);
52     p += 16;
53
54     fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : "        ");
55     if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
56     if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
57     if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
58     if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
59     if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
60     if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
61     if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
62     if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
63
64     if (master && !*master && type == 0x1d) {
65       StrnCpy(master,qname,15);
66       trim_string(master,NULL," ");
67     }
68
69     if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
70       StrnCpy(rname,qname,15);
71       trim_string(rname,NULL," ");
72     }
73       
74     for (i = strlen( qname) ; --i >= 0 ; ) {
75       if (!isprint((int)qname[i])) qname[i] = '.';
76     }
77     DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
78     p+=2;
79   }
80
81   DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
82                IVAL(p,20),IVAL(p,24)));
83 }
84
85 /****************************************************************************
86  Internal function handling a netbios name status query on a host.
87 **************************************************************************/
88
89 static BOOL internal_name_status(int fd,char *name,int name_type,BOOL recurse,
90                  struct in_addr to_ip,char *master,char *rname, BOOL verbose,
91          void (*fn_interpret_node_status)(char *, char *,char *),
92                  void (*fn)(struct packet_struct *))
93 {
94   BOOL found=False;
95   int retries = 2;
96   int retry_time = 5000;
97   struct timeval tval;
98   struct packet_struct p;
99   struct packet_struct *p2;
100   struct nmb_packet *nmb = &p.packet.nmb;
101   static int name_trn_id = 0;
102
103   memset((char *)&p,'\0',sizeof(p));
104
105   if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + 
106     ((unsigned)getpid()%(unsigned)100);
107   name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
108
109   nmb->header.name_trn_id = name_trn_id;
110   nmb->header.opcode = 0;
111   nmb->header.response = False;
112   nmb->header.nm_flags.bcast = False;
113   nmb->header.nm_flags.recursion_available = False;
114   nmb->header.nm_flags.recursion_desired = False;
115   nmb->header.nm_flags.trunc = False;
116   nmb->header.nm_flags.authoritative = False;
117   nmb->header.rcode = 0;
118   nmb->header.qdcount = 1;
119   nmb->header.ancount = 0;
120   nmb->header.nscount = 0;
121   nmb->header.arcount = 0;
122
123   make_nmb_name(&nmb->question.question_name,name,name_type,scope);
124
125   nmb->question.question_type = 0x21;
126   nmb->question.question_class = 0x1;
127
128   p.ip = to_ip;
129   p.port = NMB_PORT;
130   p.fd = fd;
131   p.timestamp = time(NULL);
132   p.packet_type = NMB_PACKET;
133
134   GetTimeOfDay(&tval);
135
136   if (!send_packet(&p)) 
137     return(False);
138
139   retries--;
140
141   while (1) {
142     struct timeval tval2;
143     GetTimeOfDay(&tval2);
144     if (TvalDiff(&tval,&tval2) > retry_time) {
145       if (!retries)
146         break;
147       if (!found && !send_packet(&p))
148         return False;
149       GetTimeOfDay(&tval);
150       retries--;
151     }
152
153     if ((p2=receive_packet(fd,NMB_PACKET,90))) {     
154       struct nmb_packet *nmb2 = &p2->packet.nmb;
155       debug_nmb_packet(p2);
156
157       if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
158              !nmb2->header.response) {
159         /* its not for us - maybe deal with it later */
160         if (fn) 
161           fn(p2);
162         else
163           free_packet(p2);
164         continue;
165       }
166           
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 redirect, but
173                we'll discard it for the moment */
174             free_packet(p2);
175             continue;
176           }
177
178       if(fn_interpret_node_status)
179             (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname);
180           free_packet(p2);
181           return(True);
182         }
183   }
184
185   if(verbose)
186     DEBUG(0,("No status response (this is not unusual)\n"));
187
188   return(False);
189 }
190
191 /****************************************************************************
192  Do a netbios name status query on a host.
193  The "master" parameter is a hack used for finding workgroups.
194 **************************************************************************/
195
196 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
197                  struct in_addr to_ip,char *master,char *rname,
198                  void (*fn)(struct packet_struct *))
199 {
200   return internal_name_status(fd,name,name_type,recurse,
201                  to_ip,master,rname,True,
202          _interpret_node_status, fn);
203 }
204
205 /****************************************************************************
206  Do a netbios name query to find someones IP.
207  Returns an array of IP addresses or NULL if none.
208  *count will be set to the number of addresses returned.
209 ****************************************************************************/
210
211 struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
212          struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
213 {
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   static int name_trn_id = 0;
222   struct in_addr *ip_list = NULL;
223
224   memset((char *)&p,'\0',sizeof(p));
225   (*count) = 0;
226
227   if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + 
228     ((unsigned)getpid()%(unsigned)100);
229   name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
230
231   nmb->header.name_trn_id = name_trn_id;
232   nmb->header.opcode = 0;
233   nmb->header.response = False;
234   nmb->header.nm_flags.bcast = bcast;
235   nmb->header.nm_flags.recursion_available = False;
236   nmb->header.nm_flags.recursion_desired = recurse;
237   nmb->header.nm_flags.trunc = False;
238   nmb->header.nm_flags.authoritative = False;
239   nmb->header.rcode = 0;
240   nmb->header.qdcount = 1;
241   nmb->header.ancount = 0;
242   nmb->header.nscount = 0;
243   nmb->header.arcount = 0;
244
245   make_nmb_name(&nmb->question.question_name,name,name_type,scope);
246
247   nmb->question.question_type = 0x20;
248   nmb->question.question_class = 0x1;
249
250   p.ip = to_ip;
251   p.port = NMB_PORT;
252   p.fd = fd;
253   p.timestamp = time(NULL);
254   p.packet_type = NMB_PACKET;
255
256   GetTimeOfDay(&tval);
257
258   if (!send_packet(&p)) 
259     return NULL;
260
261   retries--;
262
263   while (1)
264   {
265     struct timeval tval2;
266     GetTimeOfDay(&tval2);
267     if (TvalDiff(&tval,&tval2) > retry_time) 
268     {
269       if (!retries)
270         break;
271       if (!found && !send_packet(&p))
272         return NULL;
273       GetTimeOfDay(&tval);
274       retries--;
275     }
276
277     if ((p2=receive_packet(fd,NMB_PACKET,90)))
278     {     
279       struct nmb_packet *nmb2 = &p2->packet.nmb;
280       debug_nmb_packet(p2);
281
282       if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
283           !nmb2->header.response)
284       {
285         /* 
286          * Its not for us - maybe deal with it later 
287          * (put it on the queue?).
288          */
289         if (fn) 
290           fn(p2);
291         else
292           free_packet(p2);
293         continue;
294       }
295           
296       if (nmb2->header.opcode != 0 ||
297           nmb2->header.nm_flags.bcast ||
298           nmb2->header.rcode ||
299           !nmb2->header.ancount)
300       {
301             /* 
302          * XXXX what do we do with this? Could be a redirect, but
303          * we'll discard it for the moment.
304          */
305         free_packet(p2);
306         continue;
307       }
308
309       ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) * 
310                                           ((*count)+nmb2->answers->rdlength/6));
311       if (ip_list)
312       {
313         DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
314               inet_ntoa(p2->ip)));
315         for (i=0;i<nmb2->answers->rdlength/6;i++)
316         {
317           putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
318           DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
319           (*count)++;
320         }
321         DEBUG(fn?3:2,(")\n"));
322       }
323
324       found=True;
325       retries=0;
326       free_packet(p2);
327       if (fn)
328         break;
329
330       /*
331        * If we're doing a unicast lookup we only
332        * expect one reply. Don't wait the full 2
333        * seconds if we got one. JRA.
334        */
335       if(!bcast && found)
336         break;
337     }
338   }
339
340   return ip_list;
341 }
342
343 /********************************************************
344  Start parsing the lmhosts file.
345 *********************************************************/
346
347 FILE *startlmhosts(char *fname)
348 {
349   FILE *fp = sys_fopen(fname,"r");
350   if (!fp) {
351     DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
352              fname, strerror(errno)));
353     return NULL;
354   }
355   return fp;
356 }
357
358 /********************************************************
359  Parse the next line in the lmhosts file.
360 *********************************************************/
361
362 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
363 {
364   pstring line;
365
366   while(!feof(fp) && !ferror(fp)) {
367     pstring ip,flags,extra;
368     char *ptr;
369     int count = 0;
370
371     *name_type = -1;
372
373     if (!fgets_slash(line,sizeof(pstring),fp))
374       continue;
375
376     if (*line == '#')
377       continue;
378
379     pstrcpy(ip,"");
380     pstrcpy(name,"");
381     pstrcpy(flags,"");
382
383     ptr = line;
384
385     if (next_token(&ptr,ip   ,NULL,sizeof(ip)))
386       ++count;
387     if (next_token(&ptr,name ,NULL, sizeof(pstring)))
388       ++count;
389     if (next_token(&ptr,flags,NULL, sizeof(flags)))
390       ++count;
391     if (next_token(&ptr,extra,NULL, sizeof(extra)))
392       ++count;
393
394     if (count <= 0)
395       continue;
396
397     if (count > 0 && count < 2)
398     {
399       DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
400       continue;
401     }
402
403     if (count >= 4)
404     {
405       DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
406       continue;
407     }
408
409     DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
410
411     if (strchr(flags,'G') || strchr(flags,'S'))
412     {
413       DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
414       continue;
415     }
416
417     *ipaddr = *interpret_addr2(ip);
418
419     /* Extra feature. If the name ends in '#XX', where XX is a hex number,
420        then only add that name type. */
421     if((ptr = strchr(name, '#')) != NULL)
422     {
423       char *endptr;
424
425       ptr++;
426       *name_type = (int)strtol(ptr, &endptr, 16);
427
428       if(!*ptr || (endptr == ptr))
429       {
430         DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
431         continue;
432       }
433
434       *(--ptr) = '\0'; /* Truncate at the '#' */
435     }
436
437     return True;
438   }
439
440   return False;
441 }
442
443 /********************************************************
444  Finish parsing the lmhosts file.
445 *********************************************************/
446
447 void endlmhosts(FILE *fp)
448 {
449   fclose(fp);
450 }
451
452 /********************************************************
453  Resolve via "bcast" method.
454 *********************************************************/
455
456 static BOOL resolve_bcast(const char *name, int name_type,
457                                 struct in_addr **return_ip_list, int *return_count)
458 {
459         int sock, i;
460         int num_interfaces = iface_count();
461
462         *return_ip_list = NULL;
463         *return_count = 0;
464         
465         /*
466          * "bcast" means do a broadcast lookup on all the local interfaces.
467          */
468
469         DEBUG(3,("resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
470
471         sock = open_socket_in( SOCK_DGRAM, 0, 3,
472                                interpret_addr(lp_socket_address()), True );
473
474         if (sock == -1) return False;
475
476         set_socket_options(sock,"SO_BROADCAST");
477         /*
478          * Lookup the name on all the interfaces, return on
479          * the first successful match.
480          */
481         for( i = num_interfaces-1; i >= 0; i--) {
482                 struct in_addr sendto_ip;
483                 /* Done this way to fix compiler error on IRIX 5.x */
484                 sendto_ip = *iface_bcast(*iface_n_ip(i));
485                 *return_ip_list = name_query(sock, name, name_type, True, 
486                                     True, sendto_ip, return_count, NULL);
487                 if(*return_ip_list != NULL) {
488                         close(sock);
489                         return True;
490                 }
491         }
492
493         close(sock);
494         return False;
495 }
496
497 /********************************************************
498  Resolve via "wins" method.
499 *********************************************************/
500
501 static BOOL resolve_wins(const char *name, int name_type,
502                          struct in_addr **return_iplist, int *return_count)
503 {
504         int sock;
505         struct in_addr wins_ip;
506         BOOL wins_ismyip;
507
508         *return_iplist = NULL;
509         *return_count = 0;
510         
511         /*
512          * "wins" means do a unicast lookup to the WINS server.
513          * Ignore if there is no WINS server specified or if the
514          * WINS server is one of our interfaces (if we're being
515          * called from within nmbd - we can't do this call as we
516          * would then block).
517          */
518
519         DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
520
521         if(!*lp_wins_server()) {
522                 DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS server present.\n"));
523                 return False;
524         }
525
526         wins_ip = *interpret_addr2(lp_wins_server());
527         wins_ismyip = ismyip(wins_ip);
528
529         if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
530                 sock = open_socket_in( SOCK_DGRAM, 0, 3,
531                                                         interpret_addr(lp_socket_address()), True );
532               
533                 if (sock != -1) {
534                         *return_iplist = name_query(sock, name, name_type, False, 
535                                                                 True, wins_ip, return_count, NULL);
536                         if(*return_iplist != NULL) {
537                                 close(sock);
538                                 return True;
539                         }
540                         close(sock);
541                 }
542         }
543
544         return False;
545 }
546
547 /********************************************************
548  Resolve via "lmhosts" method.
549 *********************************************************/
550
551 static BOOL resolve_lmhosts(const char *name, int name_type,
552                          struct in_addr **return_iplist, int *return_count)
553 {
554         /*
555          * "lmhosts" means parse the local lmhosts file.
556          */
557         
558         FILE *fp;
559         pstring lmhost_name;
560         int name_type2;
561         struct in_addr return_ip;
562
563         *return_iplist = NULL;
564         *return_count = 0;
565
566         DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
567
568         fp = startlmhosts( LMHOSTSFILE );
569         if(fp) {
570                 while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
571                         if (strequal(name, lmhost_name) && 
572                 ((name_type2 == -1) || (name_type == name_type2))
573                ) {
574                                 endlmhosts(fp);
575                                 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
576                                 if(*return_iplist == NULL) {
577                                         DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
578                                         return False;
579                                 }
580                                 **return_iplist = return_ip;
581                                 *return_count = 1;
582                                 return True; 
583                         }
584                 }
585                 endlmhosts(fp);
586         }
587         return False;
588 }
589
590
591 /********************************************************
592  Resolve via "hosts" method.
593 *********************************************************/
594
595 static BOOL resolve_hosts(const char *name,
596                          struct in_addr **return_iplist, int *return_count)
597 {
598         /*
599          * "host" means do a localhost, or dns lookup.
600          */
601         struct hostent *hp;
602
603         *return_iplist = NULL;
604         *return_count = 0;
605
606         DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
607         
608         if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
609                 struct in_addr return_ip;
610                 putip((char *)&return_ip,(char *)hp->h_addr);
611                 *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
612                 if(*return_iplist == NULL) {
613                         DEBUG(3,("resolve_hosts: malloc fail !\n"));
614                         return False;
615                 }
616                 **return_iplist = return_ip;
617                 *return_count = 1;
618                 return True;
619         }
620         return False;
621 }
622
623 /********************************************************
624  Internal interface to resolve a name into an IP address.
625  Use this function if the string is either an IP address, DNS
626  or host name or NetBIOS name. This uses the name switch in the
627  smb.conf to determine the order of name resolution.
628 *********************************************************/
629
630 static BOOL internal_resolve_name(const char *name, int name_type,
631                                         struct in_addr **return_iplist, int *return_count)
632 {
633   pstring name_resolve_list;
634   fstring tok;
635   char *ptr;
636   BOOL allones = (strcmp(name,"255.255.255.255") == 0);
637   BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
638   BOOL is_address = is_ipaddress(name);
639   *return_iplist = NULL;
640   *return_count = 0;
641
642   if (allzeros || allones || is_address) {
643         *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
644         if(*return_iplist == NULL) {
645                 DEBUG(3,("internal_resolve_name: malloc fail !\n"));
646                 return False;
647         }
648         if(is_address) { 
649                 /* if it's in the form of an IP address then get the lib to interpret it */
650                 (*return_iplist)->s_addr = inet_addr(name);
651     } else {
652                 (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
653                 *return_count = 1;
654         }
655     return True;
656   }
657   
658   pstrcpy(name_resolve_list, lp_name_resolve_order());
659   ptr = name_resolve_list;
660   if (!ptr || !*ptr)
661     ptr = "host";
662
663   while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
664           if((strequal(tok, "host") || strequal(tok, "hosts"))) {
665                   if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) {
666                           return True;
667                   }
668           } else if(strequal( tok, "lmhosts")) {
669                   if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
670                           return True;
671                   }
672           } else if(strequal( tok, "wins")) {
673                   /* don't resolve 1D via WINS */
674                   if (name_type != 0x1D &&
675                       resolve_wins(name, name_type, return_iplist, return_count)) {
676                           return True;
677                   }
678           } else if(strequal( tok, "bcast")) {
679                   if (resolve_bcast(name, name_type, return_iplist, return_count)) {
680                           return True;
681                   }
682           } else {
683                   DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
684           }
685   }
686
687   if((*return_iplist) != NULL) {
688     free((char *)(*return_iplist));
689     *return_iplist = NULL;
690   }
691   return False;
692 }
693
694 /********************************************************
695  Internal interface to resolve a name into one IP address.
696  Use this function if the string is either an IP address, DNS
697  or host name or NetBIOS name. This uses the name switch in the
698  smb.conf to determine the order of name resolution.
699 *********************************************************/
700
701 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
702 {
703         struct in_addr *ip_list = NULL;
704         int count = 0;
705
706         if(internal_resolve_name(name, name_type, &ip_list, &count)) {
707                 *return_ip = ip_list[0];
708                 free((char *)ip_list);
709                 return True;
710         }
711         if(ip_list != NULL)
712                 free((char *)ip_list);
713         return False;
714 }
715
716 /********************************************************
717  Find the IP address of the master browser or DMB for a workgroup.
718 *********************************************************/
719
720 BOOL find_master_ip(char *group, struct in_addr *master_ip)
721 {
722         struct in_addr *ip_list = NULL;
723         int count = 0;
724
725         if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
726                 *master_ip = ip_list[0];
727                 free((char *)ip_list);
728                 return True;
729         }
730         if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
731                 *master_ip = ip_list[0];
732                 free((char *)ip_list);
733                 return True;
734         }
735
736         if(ip_list != NULL)
737                 free((char *)ip_list);
738         return False;
739 }
740
741 /********************************************************
742  Internal function to extract the MACHINE<0x20> name.
743 *********************************************************/
744
745 static void _lookup_pdc_name(char *p, char *master,char *rname)
746 {
747   int numnames = CVAL(p,0);
748
749   *rname = '\0';
750
751   p += 1;
752   while (numnames--) {
753     int type = CVAL(p,15);
754     if(type == 0x20) {
755       StrnCpy(rname,p,15);
756       trim_string(rname,NULL," ");
757       return;
758     }
759     p += 18;
760   }
761 }
762
763 /********************************************************
764  Lookup a PDC name given a Domain name and IP address.
765 *********************************************************/
766
767 BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pdc_ip, char *ret_name)
768 {
769 #if !defined(I_HATE_WINDOWS_REPLY_CODE)
770
771   fstring pdc_name;
772   BOOL ret;
773
774   /*
775    * Due to the fact win WinNT *sucks* we must do a node status
776    * query here... JRA.
777    */
778
779   int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
780
781   if(sock == -1)
782     return False;
783
784   *pdc_name = '\0';
785
786   ret = internal_name_status(sock,"*SMBSERVER",0x20,True,
787                  *pdc_ip,NULL,pdc_name,False,
788          _lookup_pdc_name,NULL);
789
790   close(sock);
791
792   if(ret && *pdc_name) {
793     fstrcpy(ret_name, pdc_name);
794     return True;
795   }
796
797   return False;
798
799 #else /* defined(I_HATE_WINDOWS_REPLY_CODE) */
800   /*
801    * Sigh. I *love* this code, it took me ages to get right and it's
802    * completely *USELESS* because NT 4.x refuses to send the mailslot
803    * reply back to the correct port (it always uses 138).
804    * I hate NT when it does these things... JRA.
805    */
806
807   int retries = 3;
808   int retry_time = 2000;
809   struct timeval tval;
810   struct packet_struct p;
811   struct dgram_packet *dgram = &p.packet.dgram;
812   char *ptr,*p2;
813   char tmp[4];
814   int len;
815   struct sockaddr_in sock_name;
816   int sock_len = sizeof(sock_name);
817   const char *mailslot = "\\MAILSLOT\\NET\\NETLOGON";
818   static int name_trn_id = 0;
819   char buffer[1024];
820   char *bufp;
821   int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
822
823   if(sock == -1)
824     return False;
825
826   /* Find out the transient UDP port we have been allocated. */
827   if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
828     DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
829             strerror(errno)));
830     close(sock);
831     return False;
832   }
833
834   /*
835    * Create the request data.
836    */
837
838   memset(buffer,'\0',sizeof(buffer));
839   bufp = buffer;
840   SSVAL(bufp,0,QUERYFORPDC);
841   bufp += 2;
842   fstrcpy(bufp,srcname);
843   bufp += (strlen(bufp) + 1);
844   fstrcpy(bufp,"\\MAILSLOT\\NET\\GETDC411");
845   bufp += (strlen(bufp) + 1);
846   bufp = align2(bufp, buffer);
847   dos_PutUniCode(bufp, srcname, sizeof(buffer) - (bufp - buffer) - 1);
848   bufp = skip_unicode_string(bufp, 1);
849   SIVAL(bufp,0,1);
850   SSVAL(bufp,4,0xFFFF); 
851   SSVAL(bufp,6,0xFFFF); 
852   bufp += 8;
853   len = PTR_DIFF(bufp,buffer);
854
855   if (!name_trn_id)
856     name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)getpid()%(unsigned)100);
857   name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
858
859   memset((char *)&p,'\0',sizeof(p));
860
861   /* DIRECT GROUP or UNIQUE datagram. */
862   dgram->header.msg_type = 0x10;
863   dgram->header.flags.node_type = M_NODE;
864   dgram->header.flags.first = True;
865   dgram->header.flags.more = False;
866   dgram->header.dgm_id = name_trn_id;
867   dgram->header.source_ip = sock_name.sin_addr;
868   dgram->header.source_port = ntohs(sock_name.sin_port);
869   dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
870   dgram->header.packet_offset = 0;
871  
872   make_nmb_name(&dgram->source_name,srcname,0,scope);
873   make_nmb_name(&dgram->dest_name,domain,0x1B,scope);
874
875   ptr = &dgram->data[0];
876
877   /* Setup the smb part. */
878   ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
879   memcpy(tmp,ptr,4);
880   set_message(ptr,17,17 + len,True);
881   memcpy(ptr,tmp,4);
882
883   CVAL(ptr,smb_com) = SMBtrans;
884   SSVAL(ptr,smb_vwv1,len);
885   SSVAL(ptr,smb_vwv11,len);
886   SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
887   SSVAL(ptr,smb_vwv13,3);
888   SSVAL(ptr,smb_vwv14,1);
889   SSVAL(ptr,smb_vwv15,1);
890   SSVAL(ptr,smb_vwv16,2);
891   p2 = smb_buf(ptr);
892   pstrcpy(p2,mailslot);
893   p2 = skip_string(p2,1);
894
895   memcpy(p2,buffer,len);
896   p2 += len;
897
898   dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
899
900   p.ip = *pdc_ip;
901   p.port = DGRAM_PORT;
902   p.fd = sock;
903   p.timestamp = time(NULL);
904   p.packet_type = DGRAM_PACKET;
905
906   GetTimeOfDay(&tval);
907
908   if (!send_packet(&p)) {
909     DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
910     close(sock);
911     return False;
912   }
913
914   retries--;
915
916   while (1) {
917     struct timeval tval2;
918     struct packet_struct *p_ret;
919
920     GetTimeOfDay(&tval2);
921     if (TvalDiff(&tval,&tval2) > retry_time) {
922       if (!retries)
923         break;
924       if (!send_packet(&p)) {
925         DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
926         close(sock);
927         return False;
928       }
929       GetTimeOfDay(&tval);
930       retries--;
931     }
932
933     if ((p_ret = receive_packet(sock,NMB_PACKET,90))) {
934       struct nmb_packet *nmb2 = &p_ret->packet.nmb;
935       struct dgram_packet *dgram2 = &p_ret->packet.dgram;
936       char *buf;
937       char *buf2;
938
939       debug_nmb_packet(p_ret);
940
941       if (memcmp(&p.ip, &p_ret->ip, sizeof(p.ip))) {
942         /* 
943          * Not for us.
944          */
945         DEBUG(0,("lookup_pdc_name: datagram return IP %s doesn't match\n", inet_ntoa(p_ret->ip) ));
946         free_packet(p_ret);
947         continue;
948       }
949
950       buf = &dgram2->data[0];
951       buf -= 4;
952
953       if (CVAL(buf,smb_com) != SMBtrans) {
954         DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)CVAL(buf,smb_com),
955               (unsigned int)SMBtrans ));
956         free_packet(p_ret);
957         continue;
958       }
959
960       len = SVAL(buf,smb_vwv11);
961       buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
962
963       if (len <= 0) {
964         DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
965         free_packet(p_ret);
966         continue;
967       }
968
969       DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
970        nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
971        inet_ntoa(p_ret->ip), smb_buf(buf),CVAL(buf2,0),len));
972
973       if(SVAL(buf,0) != QUERYFORPDC_R) {
974         DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
975               (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
976         free_packet(p_ret);
977         continue;
978       }
979
980       buf += 2;
981       /* Note this is safe as it is a bounded strcpy. */
982       fstrcpy(ret_name, buf);
983       ret_name[sizeof(fstring)-1] = '\0';
984       close(sock);
985       free_packet(p_ret);
986       return True;
987     }
988   }
989
990   close(sock);
991   return False;
992 #endif /* I_HATE_WINDOWS_REPLY_CODE */
993 }
994
995 /********************************************************
996  Get the IP address list of the PDC/BDC's of a Domain.
997 *********************************************************/
998
999 BOOL get_dc_list(char *group, struct in_addr **ip_list, int *count)
1000 {
1001         return internal_resolve_name(group, 0x1C, ip_list, count);
1002 }