Replaced "\\MAILSLOT\\NET\\NETLOGON" with NET_LOGON_MAILSLOT constant.
[tprouty/samba.git] / source / 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 int DEBUGLEVEL;
26
27 /* nmbd.c sets this to True. */
28 BOOL global_in_nmbd = False;
29
30 /****************************************************************************
31 generate a random trn_id
32 ****************************************************************************/
33 static int generate_trn_id(void)
34 {
35         static int trn_id;
36
37         if (trn_id == 0) {
38                 sys_srandom(sys_getpid());
39         }
40
41         trn_id = sys_random();
42
43         return trn_id % (unsigned)0x7FFF;
44 }
45
46
47 /****************************************************************************
48  Interpret a node status response.
49 ****************************************************************************/
50
51 static void _interpret_node_status(char *p, char *master,char *rname)
52 {
53   int numnames = CVAL(p,0);
54   DEBUG(1,("received %d names\n",numnames));
55
56   if (rname) *rname = 0;
57   if (master) *master = 0;
58
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;
69
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> ");
79
80     if (master && !*master && type == 0x1d) {
81       StrnCpy(master,qname,15);
82       trim_string(master,NULL," ");
83     }
84
85     if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
86       StrnCpy(rname,qname,15);
87       trim_string(rname,NULL," ");
88     }
89       
90     for (i = strlen( qname) ; --i >= 0 ; ) {
91       if (!isprint((int)qname[i])) qname[i] = '.';
92     }
93     DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
94     p+=2;
95   }
96
97   DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
98                IVAL(p,20),IVAL(p,24)));
99 }
100
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 *))
108 {
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;
116
117   memset((char *)&p,'\0',sizeof(p));
118
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;
132
133   make_nmb_name(&nmb->question.question_name,name,name_type);
134
135   nmb->question.question_type = 0x21;
136   nmb->question.question_class = 0x1;
137
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;
143
144   GetTimeOfDay(&tval);
145
146   if (!send_packet(&p)) 
147     return(False);
148
149   retries--;
150
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--;
161           }
162
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);
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
173                              redirect, but we'll discard it for the
174                              moment */
175                           free_packet(p2);
176                           continue;
177                   }
178
179                   if(fn_interpret_node_status)
180                           (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname);
181                   free_packet(p2);
182                   return(True);
183           }
184   }
185
186   if(verbose)
187           DEBUG(0,("No status response (this is not unusual)\n"));
188
189   return(False);
190 }
191
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)
198 {
199         return internal_name_status(fd,name,name_type,recurse,
200                                     to_ip,master,rname,True,
201                                     _interpret_node_status);
202 }
203
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 ****************************************************************************/
209
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)
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   struct in_addr *ip_list = NULL;
222
223   memset((char *)&p,'\0',sizeof(p));
224   (*count) = 0;
225
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;
239
240   make_nmb_name(&nmb->question.question_name,name,name_type);
241
242   nmb->question.question_type = 0x20;
243   nmb->question.question_class = 0x1;
244
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;
250
251   GetTimeOfDay(&tval);
252
253   if (!send_packet(&p)) 
254     return NULL;
255
256   retries--;
257
258   while (1)
259   {
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--;
269           }
270           
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);
274
275                   /* If we get a Negative Name Query Response from a WINS
276                    * server, we should report it and give up.
277                    */
278                   if( 0 == nmb2->header.opcode          /* A query response   */
279                       && !(bcast)                       /* from a WINS server */
280                       && nmb2->header.rcode             /* Error returned     */
281                     ) {
282
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;
306                       }
307                     }
308                     free_packet(p2);
309                     return( NULL );
310                   }
311
312                   if (nmb2->header.opcode != 0 ||
313                       nmb2->header.nm_flags.bcast ||
314                       nmb2->header.rcode ||
315                       !nmb2->header.ancount) {
316                           /* 
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;
322                   }
323
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)++;
334                           }
335                           DEBUGADD(2,(")\n"));
336                   }
337
338                   found=True;
339                   retries=0;
340                   free_packet(p2);
341                   /*
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.
345                    */
346                   if(!bcast && found)
347                           break;
348           }
349   }
350
351   /* Reach here if we've timed out waiting for replies.. */
352   if( !bcast && !found )
353     {
354     /* Timed out wating for WINS server to respond.  Mark it dead. */
355     wins_srv_died( to_ip );
356     }
357
358   return ip_list;
359 }
360
361 /********************************************************
362  Start parsing the lmhosts file.
363 *********************************************************/
364
365 FILE *startlmhosts(char *fname)
366 {
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;
372   }
373   return fp;
374 }
375
376 /********************************************************
377  Parse the next line in the lmhosts file.
378 *********************************************************/
379
380 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
381 {
382   pstring line;
383
384   while(!feof(fp) && !ferror(fp)) {
385     pstring ip,flags,extra;
386     char *ptr;
387     int count = 0;
388
389     *name_type = -1;
390
391     if (!fgets_slash(line,sizeof(pstring),fp))
392       continue;
393
394     if (*line == '#')
395       continue;
396
397     pstrcpy(ip,"");
398     pstrcpy(name,"");
399     pstrcpy(flags,"");
400
401     ptr = line;
402
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;
411
412     if (count <= 0)
413       continue;
414
415     if (count > 0 && count < 2)
416     {
417       DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
418       continue;
419     }
420
421     if (count >= 4)
422     {
423       DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
424       continue;
425     }
426
427     DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
428
429     if (strchr(flags,'G') || strchr(flags,'S'))
430     {
431       DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
432       continue;
433     }
434
435     *ipaddr = *interpret_addr2(ip);
436
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)
440     {
441       char *endptr;
442
443       ptr++;
444       *name_type = (int)strtol(ptr, &endptr, 16);
445
446       if(!*ptr || (endptr == ptr))
447       {
448         DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
449         continue;
450       }
451
452       *(--ptr) = '\0'; /* Truncate at the '#' */
453     }
454
455     return True;
456   }
457
458   return False;
459 }
460
461 /********************************************************
462  Finish parsing the lmhosts file.
463 *********************************************************/
464
465 void endlmhosts(FILE *fp)
466 {
467   fclose(fp);
468 }
469
470 /********************************************************
471  Resolve via "bcast" method.
472 *********************************************************/
473
474 static BOOL resolve_bcast(const char *name, int name_type,
475                                 struct in_addr **return_ip_list, int *return_count)
476 {
477         int sock, i;
478         int num_interfaces = iface_count();
479
480         *return_ip_list = NULL;
481         *return_count = 0;
482         
483         /*
484          * "bcast" means do a broadcast lookup on all the local interfaces.
485          */
486
487         DEBUG(3,("resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
488
489         sock = open_socket_in( SOCK_DGRAM, 0, 3,
490                                interpret_addr(lp_socket_address()), True );
491
492         if (sock == -1) return False;
493
494         set_socket_options(sock,"SO_BROADCAST");
495         /*
496          * Lookup the name on all the interfaces, return on
497          * the first successful match.
498          */
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;
508                 }
509         }
510
511         close(sock);
512         return False;
513 }
514
515 /********************************************************
516  Resolve via "wins" method.
517 *********************************************************/
518
519 static BOOL resolve_wins(const char *name, int name_type,
520                          struct in_addr **return_iplist, int *return_count)
521 {
522         int sock;
523         struct in_addr wins_ip;
524         BOOL wins_ismyip;
525
526         *return_iplist = NULL;
527         *return_count = 0;
528         
529         /*
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).
535          */
536
537         DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
538
539         if( wins_srv_count() < 1 ) {
540                 DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
541                 return False;
542         }
543
544         wins_ip     = wins_srv_ip();
545         wins_ismyip = ismyip(wins_ip);
546
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;
560                         }
561                         close(sock);
562                 }
563         }
564
565         return False;
566 }
567
568 /********************************************************
569  Resolve via "lmhosts" method.
570 *********************************************************/
571
572 static BOOL resolve_lmhosts(const char *name, int name_type,
573                          struct in_addr **return_iplist, int *return_count)
574 {
575         /*
576          * "lmhosts" means parse the local lmhosts file.
577          */
578         
579         FILE *fp;
580         pstring lmhost_name;
581         int name_type2;
582         struct in_addr return_ip;
583
584         *return_iplist = NULL;
585         *return_count = 0;
586
587         DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
588
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))
594                ) {
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;
600                                 }
601                                 **return_iplist = return_ip;
602                                 *return_count = 1;
603                                 return True; 
604                         }
605                 }
606                 endlmhosts(fp);
607         }
608         return False;
609 }
610
611
612 /********************************************************
613  Resolve via "hosts" method.
614 *********************************************************/
615
616 static BOOL resolve_hosts(const char *name,
617                          struct in_addr **return_iplist, int *return_count)
618 {
619         /*
620          * "host" means do a localhost, or dns lookup.
621          */
622         struct hostent *hp;
623
624         *return_iplist = NULL;
625         *return_count = 0;
626
627         DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
628         
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;
636                 }
637                 **return_iplist = return_ip;
638                 *return_count = 1;
639                 return True;
640         }
641         return False;
642 }
643
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)
651 {
652   int i;
653   for (i=0; name[i]; i++)
654     if (!(isdigit((int)name[i]) || name[i] == '.'))
655         return False;
656
657   return True;
658 }
659
660
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 *********************************************************/
667
668 static BOOL internal_resolve_name(const char *name, int name_type,
669                                         struct in_addr **return_iplist, int *return_count)
670 {
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;
679
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;
685         }
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;
692         }
693     return True;
694   }
695   
696   pstrcpy(name_resolve_list, lp_name_resolve_order());
697   ptr = name_resolve_list;
698   if (!ptr || !*ptr)
699     ptr = "host";
700
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;
705                   }
706           } else if(strequal( tok, "lmhosts")) {
707                   if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
708                           return True;
709                   }
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;
715                   }
716           } else if(strequal( tok, "bcast")) {
717                   if (resolve_bcast(name, name_type, return_iplist, return_count)) {
718                           return True;
719                   }
720           } else {
721                   DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
722           }
723   }
724
725   if((*return_iplist) != NULL) {
726     free((char *)(*return_iplist));
727     *return_iplist = NULL;
728   }
729   return False;
730 }
731
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 *********************************************************/
738
739 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
740 {
741         struct in_addr *ip_list = NULL;
742         int count = 0;
743
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;
748         }
749         if(ip_list != NULL)
750                 free((char *)ip_list);
751         return False;
752 }
753
754
755 /********************************************************
756  resolve a name of format \\server_name or \\ipaddress
757  into a name.  also, cut the \\ from the front for us.
758 *********************************************************/
759
760 BOOL resolve_srv_name(const char* srv_name, fstring dest_host,
761                                 struct in_addr *ip)
762 {
763         BOOL ret;
764         const char *sv_name = srv_name;
765
766         DEBUG(10,("resolve_srv_name: %s\n", srv_name));
767
768         if (srv_name == NULL || strequal("\\\\.", srv_name))
769         {
770                 extern pstring global_myname;
771                 fstrcpy(dest_host, global_myname);
772                 ip = interpret_addr2("127.0.0.1");
773                 return True;
774         }
775
776         if (strnequal("\\\\", srv_name, 2))
777         {
778                 sv_name = &srv_name[2];
779         }
780
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);
789         }
790         
791         if (is_ip_address(dest_host))
792         {
793                 fstrcpy(dest_host, "*SMBSERVER");
794         }
795         
796         return ret;
797 }
798
799
800 /********************************************************
801  Find the IP address of the master browser or DMB for a workgroup.
802 *********************************************************/
803
804 BOOL find_master_ip(char *group, struct in_addr *master_ip)
805 {
806         struct in_addr *ip_list = NULL;
807         int count = 0;
808
809         if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
810                 *master_ip = ip_list[0];
811                 free((char *)ip_list);
812                 return True;
813         }
814         if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
815                 *master_ip = ip_list[0];
816                 free((char *)ip_list);
817                 return True;
818         }
819
820         if(ip_list != NULL)
821                 free((char *)ip_list);
822         return False;
823 }
824
825
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)
830 {
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 = NET_LOGON_MAILSLOT;
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 );
847         
848         if(sock == -1)
849                 return False;
850         
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;
857         }
858
859         /*
860          * Create the request data.
861          */
862
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);
879
880         memset((char *)&p,'\0',sizeof(p));
881
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;
892         
893         make_nmb_name(&dgram->source_name,srcname,0);
894         make_nmb_name(&dgram->dest_name,domain,0x1B);
895         
896         ptr = &dgram->data[0];
897         
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);
903
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);
915         
916         memcpy(p2,buffer,len);
917         p2 += len;
918         
919         dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
920         
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;
926         
927         GetTimeOfDay(&tval);
928         
929         if (!send_packet(&p)) {
930                 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
931                 close(sock);
932                 return False;
933         }
934         
935         retries--;
936         
937         while (1) {
938                 struct timeval tval2;
939                 struct packet_struct *p_ret;
940                 
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;
949                         }
950                         GetTimeOfDay(&tval);
951                         retries--;
952                 }
953
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;
958
959                         buf = &dgram2->data[0];
960                         buf -= 4;
961
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;
967                         }
968                         
969                         len = SVAL(buf,smb_vwv11);
970                         buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
971                         
972                         if (len <= 0) {
973                                 DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
974                                 free_packet(p_ret);
975                                 continue;
976                         }
977
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));
981
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;
987                         }
988
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;
996                 }
997         }
998         
999         close(sock);
1000         return False;
1001 }
1002
1003
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)
1008 {
1009         return internal_resolve_name(group, 0x1C, ip_list, count);
1010 }