Rolled back find NetBIOS name of PDC/BDC code as a temp fix. This
[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 = 2000;
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 #if !defined(I_HATE_WINDOWS_REPLY_CODE)
826 /********************************************************
827  Internal function to extract the MACHINE<0x20> name.
828 *********************************************************/
829
830 static void _lookup_pdc_name(char *p, char *master,char *rname)
831 {
832   int numnames = CVAL(p,0);
833
834   *rname = '\0';
835
836   p += 1;
837   while (numnames--) {
838     int type = CVAL(p,15);
839     if(type == 0x20) {
840       StrnCpy(rname,p,15);
841       trim_string(rname,NULL," ");
842       return;
843     }
844     p += 18;
845   }
846 }
847 #endif /* I_HATE_WINDOWS_REPLY_CODE */
848
849 /********************************************************
850  Lookup a PDC name given a Domain name and IP address.
851 *********************************************************/
852
853 BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pdc_ip, char *ret_name)
854 {
855 #if !defined(I_HATE_WINDOWS_REPLY_CODE)
856
857   fstring pdc_name;
858   BOOL ret;
859
860   /*
861    * Due to the fact win WinNT *sucks* we must do a node status
862    * query here... JRA.
863    */
864
865   int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
866
867   if(sock == -1)
868     return False;
869
870   *pdc_name = '\0';
871
872   ret = internal_name_status(sock,"*SMBSERVER",0x20,True,
873                  *pdc_ip,NULL,pdc_name,False,_lookup_pdc_name);
874
875   close(sock);
876
877   if(ret && *pdc_name) {
878     fstrcpy(ret_name, pdc_name);
879     return True;
880   }
881
882   return False;
883
884 #else /* defined(I_HATE_WINDOWS_REPLY_CODE) */
885
886 JRA - This code is broken with BDC rollover - we need to do a full
887 NT GETDC call, UNICODE, NT domain SID and uncle tom cobbley and all...
888
889         int retries = 3;
890         int retry_time = 2000;
891         struct timeval tval;
892         struct packet_struct p;
893         struct dgram_packet *dgram = &p.packet.dgram;
894         char *ptr,*p2;
895         char tmp[4];
896         int len;
897         struct sockaddr_in sock_name;
898         int sock_len = sizeof(sock_name);
899         const char *mailslot = NET_LOGON_MAILSLOT;
900         char *mailslot_name;
901         char buffer[1024];
902         char *bufp;
903         int dgm_id = generate_trn_id();
904         int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
905         
906         if(sock == -1)
907                 return False;
908         
909         /* Find out the transient UDP port we have been allocated. */
910         if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
911                 DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
912                          strerror(errno)));
913                 close(sock);
914                 return False;
915         }
916
917         /*
918          * Create the request data.
919          */
920
921         memset(buffer,'\0',sizeof(buffer));
922         bufp = buffer;
923         SSVAL(bufp,0,QUERYFORPDC);
924         bufp += 2;
925         fstrcpy(bufp,srcname);
926         bufp += (strlen(bufp) + 1);
927         slprintf(bufp, sizeof(fstring), "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
928         mailslot_name = bufp;
929         bufp += (strlen(bufp) + 1);
930         bufp = ALIGN2(bufp, buffer);
931         bufp += dos_PutUniCode(bufp, srcname, sizeof(buffer) - (bufp - buffer) - 1, True);
932         SIVAL(bufp,0,1);
933         SSVAL(bufp,4,0xFFFF); 
934         SSVAL(bufp,6,0xFFFF); 
935         bufp += 8;
936         len = PTR_DIFF(bufp,buffer);
937
938         memset((char *)&p,'\0',sizeof(p));
939
940         /* DIRECT GROUP or UNIQUE datagram. */
941         dgram->header.msg_type = 0x10;
942         dgram->header.flags.node_type = M_NODE;
943         dgram->header.flags.first = True;
944         dgram->header.flags.more = False;
945         dgram->header.dgm_id = dgm_id;
946         dgram->header.source_ip = *iface_ip(*pdc_ip);
947         dgram->header.source_port = ntohs(sock_name.sin_port);
948         dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
949         dgram->header.packet_offset = 0;
950         
951         make_nmb_name(&dgram->source_name,srcname,0);
952         make_nmb_name(&dgram->dest_name,domain,0x1C);
953         
954         ptr = &dgram->data[0];
955         
956         /* Setup the smb part. */
957         ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
958         memcpy(tmp,ptr,4);
959         set_message(ptr,17,17 + len,True);
960         memcpy(ptr,tmp,4);
961
962         CVAL(ptr,smb_com) = SMBtrans;
963         SSVAL(ptr,smb_vwv1,len);
964         SSVAL(ptr,smb_vwv11,len);
965         SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
966         SSVAL(ptr,smb_vwv13,3);
967         SSVAL(ptr,smb_vwv14,1);
968         SSVAL(ptr,smb_vwv15,1);
969         SSVAL(ptr,smb_vwv16,2);
970         p2 = smb_buf(ptr);
971         pstrcpy(p2,mailslot);
972         p2 = skip_string(p2,1);
973         
974         memcpy(p2,buffer,len);
975         p2 += len;
976         
977         dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
978         
979         p.ip = *pdc_ip;
980         p.port = DGRAM_PORT;
981         p.fd = sock;
982         p.timestamp = time(NULL);
983         p.packet_type = DGRAM_PACKET;
984         
985         GetTimeOfDay(&tval);
986         
987         if (!send_packet(&p)) {
988                 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
989                 close(sock);
990                 return False;
991         }
992         
993         retries--;
994         
995         while (1) {
996                 struct timeval tval2;
997                 struct packet_struct *p_ret;
998                 
999                 GetTimeOfDay(&tval2);
1000                 if (TvalDiff(&tval,&tval2) > retry_time) {
1001                         if (!retries)
1002                                 break;
1003                         if (!send_packet(&p)) {
1004                                 DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
1005                                 close(sock);
1006                                 return False;
1007                         }
1008                         GetTimeOfDay(&tval);
1009                         retries--;
1010                 }
1011
1012                 if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
1013                         struct dgram_packet *dgram2 = &p_ret->packet.dgram;
1014                         char *buf;
1015                         char *buf2;
1016
1017                         buf = &dgram2->data[0];
1018                         buf -= 4;
1019
1020                         if (CVAL(buf,smb_com) != SMBtrans) {
1021                                 DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)
1022                                          CVAL(buf,smb_com), (unsigned int)SMBtrans ));
1023                                 free_packet(p_ret);
1024                                 continue;
1025                         }
1026                         
1027                         len = SVAL(buf,smb_vwv11);
1028                         buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
1029                         
1030                         if (len <= 0) {
1031                                 DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
1032                                 free_packet(p_ret);
1033                                 continue;
1034                         }
1035
1036                         DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
1037                                  nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
1038                                  inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len));
1039
1040                         if(SVAL(buf2,0) != QUERYFORPDC_R) {
1041                                 DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
1042                                          (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
1043                                 free_packet(p_ret);
1044                                 continue;
1045                         }
1046
1047                         buf2 += 2;
1048                         /* Note this is safe as it is a bounded strcpy. */
1049                         fstrcpy(ret_name, buf2);
1050                         ret_name[sizeof(fstring)-1] = '\0';
1051                         close(sock);
1052                         free_packet(p_ret);
1053                         return True;
1054                 }
1055         }
1056         
1057         close(sock);
1058         return False;
1059 #endif /* defined(I_HATE_WINDOWS_REPLY_CODE) */
1060 }
1061
1062
1063 /********************************************************
1064  Get the IP address list of the PDC/BDC's of a Domain.
1065 *********************************************************/
1066 BOOL get_dc_list(char *group, struct in_addr **ip_list, int *count)
1067 {
1068         return internal_resolve_name(group, 0x1C, ip_list, count);
1069 }