In security=user mode we must allow cli_connect_serverlist to connect to our
[samba.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 static void _interpret_node_status(char *p, char *master,char *rname)
35 {
36   int numnames = CVAL(p,0);
37   DEBUG(1,("received %d names\n",numnames));
38
39   if (rname) *rname = 0;
40   if (master) *master = 0;
41
42   p += 1;
43   while (numnames--)
44     {
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   DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
81                IVAL(p,20),IVAL(p,24)));
82 }
83
84
85 /****************************************************************************
86   do a netbios name status query on a host
87
88   the "master" parameter is a hack used for finding workgroups.
89   **************************************************************************/
90 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
91                  struct in_addr to_ip,char *master,char *rname,
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   bzero((char *)&p,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     {
143       struct timeval tval2;
144       GetTimeOfDay(&tval2);
145       if (TvalDiff(&tval,&tval2) > retry_time) {
146         if (!retries) 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         {     
155           struct nmb_packet *nmb2 = &p2->packet.nmb;
156       debug_nmb_packet(p2);
157
158           if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
159               !nmb2->header.response) {
160             /* its not for us - maybe deal with it later */
161             if (fn) 
162               fn(p2);
163             else
164               free_packet(p2);
165             continue;
166           }
167           
168           if (nmb2->header.opcode != 0 ||
169               nmb2->header.nm_flags.bcast ||
170               nmb2->header.rcode ||
171               !nmb2->header.ancount ||
172               nmb2->answers->rr_type != 0x21) {
173             /* XXXX what do we do with this? could be a redirect, but
174                we'll discard it for the moment */
175             free_packet(p2);
176             continue;
177           }
178
179           _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
180           free_packet(p2);
181           return(True);
182         }
183     }
184   
185
186   DEBUG(0,("No status response (this is not unusual)\n"));
187
188   return(False);
189 }
190
191
192 /****************************************************************************
193   do a netbios name query to find someones IP
194   returns an array of IP addresses or NULL if none
195   *count will be set to the number of addresses returned
196   ****************************************************************************/
197 struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
198          struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
199 {
200   BOOL found=False;
201   int i, retries = 3;
202   int retry_time = bcast?250:2000;
203   struct timeval tval;
204   struct packet_struct p;
205   struct packet_struct *p2;
206   struct nmb_packet *nmb = &p.packet.nmb;
207   static int name_trn_id = 0;
208   struct in_addr *ip_list = NULL;
209
210   bzero((char *)&p,sizeof(p));
211   (*count) = 0;
212
213   if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + 
214     ((unsigned)getpid()%(unsigned)100);
215   name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
216
217   nmb->header.name_trn_id = name_trn_id;
218   nmb->header.opcode = 0;
219   nmb->header.response = False;
220   nmb->header.nm_flags.bcast = bcast;
221   nmb->header.nm_flags.recursion_available = False;
222   nmb->header.nm_flags.recursion_desired = recurse;
223   nmb->header.nm_flags.trunc = False;
224   nmb->header.nm_flags.authoritative = False;
225   nmb->header.rcode = 0;
226   nmb->header.qdcount = 1;
227   nmb->header.ancount = 0;
228   nmb->header.nscount = 0;
229   nmb->header.arcount = 0;
230
231   make_nmb_name(&nmb->question.question_name,name,name_type,scope);
232
233   nmb->question.question_type = 0x20;
234   nmb->question.question_class = 0x1;
235
236   p.ip = to_ip;
237   p.port = NMB_PORT;
238   p.fd = fd;
239   p.timestamp = time(NULL);
240   p.packet_type = NMB_PACKET;
241
242   GetTimeOfDay(&tval);
243
244   if (!send_packet(&p)) 
245     return NULL;
246
247   retries--;
248
249   while (1)
250   {
251     struct timeval tval2;
252     GetTimeOfDay(&tval2);
253     if (TvalDiff(&tval,&tval2) > retry_time) 
254     {
255       if (!retries)
256         break;
257       if (!found && !send_packet(&p))
258         return NULL;
259       GetTimeOfDay(&tval);
260       retries--;
261     }
262
263     if ((p2=receive_packet(fd,NMB_PACKET,90)))
264     {     
265       struct nmb_packet *nmb2 = &p2->packet.nmb;
266       debug_nmb_packet(p2);
267
268       if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
269           !nmb2->header.response)
270       {
271         /* 
272          * Its not for us - maybe deal with it later 
273          * (put it on the queue?).
274          */
275         if (fn) 
276           fn(p2);
277         else
278           free_packet(p2);
279         continue;
280       }
281           
282       if (nmb2->header.opcode != 0 ||
283           nmb2->header.nm_flags.bcast ||
284           nmb2->header.rcode ||
285           !nmb2->header.ancount)
286       {
287             /* 
288          * XXXX what do we do with this? Could be a redirect, but
289          * we'll discard it for the moment.
290          */
291         free_packet(p2);
292         continue;
293       }
294
295       ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) * 
296                                           ((*count)+nmb2->answers->rdlength/6));
297       if (ip_list)
298       {
299         DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
300               inet_ntoa(p2->ip)));
301         for (i=0;i<nmb2->answers->rdlength/6;i++)
302         {
303           putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
304           DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
305           (*count)++;
306         }
307         DEBUG(fn?3:2,(")\n"));
308       }
309
310       found=True;
311       retries=0;
312       free_packet(p2);
313       if (fn)
314         break;
315
316       /*
317        * If we're doing a unicast lookup we only
318        * expect one reply. Don't wait the full 2
319        * seconds if we got one. JRA.
320        */
321       if(!bcast && found)
322         break;
323     }
324   }
325
326   return ip_list;
327 }
328
329 /********************************************************
330  Start parsing the lmhosts file.
331 *********************************************************/
332
333 FILE *startlmhosts(char *fname)
334 {
335   FILE *fp = sys_fopen(fname,"r");
336   if (!fp) {
337     DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
338              fname, strerror(errno)));
339     return NULL;
340   }
341   return fp;
342 }
343
344 /********************************************************
345  Parse the next line in the lmhosts file.
346 *********************************************************/
347 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
348 {
349   pstring line;
350
351   while(!feof(fp) && !ferror(fp)) {
352     pstring ip,flags,extra;
353     char *ptr;
354     int count = 0;
355
356     *name_type = -1;
357
358     if (!fgets_slash(line,sizeof(pstring),fp))
359       continue;
360
361     if (*line == '#')
362       continue;
363
364     pstrcpy(ip,"");
365     pstrcpy(name,"");
366     pstrcpy(flags,"");
367
368     ptr = line;
369
370     if (next_token(&ptr,ip   ,NULL,sizeof(ip)))
371       ++count;
372     if (next_token(&ptr,name ,NULL, sizeof(pstring)))
373       ++count;
374     if (next_token(&ptr,flags,NULL, sizeof(flags)))
375       ++count;
376     if (next_token(&ptr,extra,NULL, sizeof(extra)))
377       ++count;
378
379     if (count <= 0)
380       continue;
381
382     if (count > 0 && count < 2)
383     {
384       DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
385       continue;
386     }
387
388     if (count >= 4)
389     {
390       DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
391       continue;
392     }
393
394     DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
395
396     if (strchr(flags,'G') || strchr(flags,'S'))
397     {
398       DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
399       continue;
400     }
401
402     *ipaddr = *interpret_addr2(ip);
403
404     /* Extra feature. If the name ends in '#XX', where XX is a hex number,
405        then only add that name type. */
406     if((ptr = strchr(name, '#')) != NULL)
407     {
408       char *endptr;
409
410       ptr++;
411       *name_type = (int)strtol(ptr, &endptr,0);
412
413       if(!*ptr || (endptr == ptr))
414       {
415         DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
416         continue;
417       }
418
419       *(--ptr) = '\0'; /* Truncate at the '#' */
420     }
421
422     return True;
423   }
424
425   return False;
426 }
427
428 /********************************************************
429  Finish parsing the lmhosts file.
430 *********************************************************/
431
432 void endlmhosts(FILE *fp)
433 {
434   fclose(fp);
435 }
436
437
438
439 /********************************************************
440 resolve via "bcast" method
441 *********************************************************/
442 static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
443 {
444         int sock, i;
445         
446         /*
447          * "bcast" means do a broadcast lookup on all the local interfaces.
448          */
449
450         DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
451
452         sock = open_socket_in( SOCK_DGRAM, 0, 3,
453                                interpret_addr(lp_socket_address()) );
454
455         if (sock != -1) {
456                 struct in_addr *iplist = NULL;
457                 int count;
458                 int num_interfaces = iface_count();
459                 set_socket_options(sock,"SO_BROADCAST");
460                 /*
461                  * Lookup the name on all the interfaces, return on
462                  * the first successful match.
463                  */
464                 for( i = 0; i < num_interfaces; i++) {
465                         struct in_addr sendto_ip;
466                         /* Done this way to fix compiler error on IRIX 5.x */
467                         sendto_ip = *iface_bcast(*iface_n_ip(i));
468                         iplist = name_query(sock, name, name_type, True, 
469                                             True, sendto_ip, &count, NULL);
470                         if(iplist != NULL) {
471                                 *return_ip = iplist[0];
472                                 free((char *)iplist);
473                                 close(sock);
474                                 return True;
475                         }
476                 }
477                 close(sock);
478         }
479
480         return False;
481 }
482
483
484
485 /********************************************************
486 resolve via "wins" method
487 *********************************************************/
488 static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
489 {
490       int sock;
491       struct in_addr wins_ip;
492       BOOL wins_ismyip;
493
494       /*
495        * "wins" means do a unicast lookup to the WINS server.
496        * Ignore if there is no WINS server specified or if the
497        * WINS server is one of our interfaces (if we're being
498        * called from within nmbd - we can't do this call as we
499        * would then block).
500        */
501
502       DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
503
504       if(!*lp_wins_server()) {
505               DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
506               return False;
507       }
508
509       wins_ip = *interpret_addr2(lp_wins_server());
510       wins_ismyip = ismyip(wins_ip);
511
512       if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
513               sock = open_socket_in( SOCK_DGRAM, 0, 3,
514                                      interpret_addr(lp_socket_address()) );
515               
516               if (sock != -1) {
517                       struct in_addr *iplist = NULL;
518                       int count;
519                       iplist = name_query(sock, name, name_type, False, 
520                                           True, wins_ip, &count, NULL);
521                       if(iplist != NULL) {
522                               *return_ip = iplist[0];
523                               free((char *)iplist);
524                               close(sock);
525                               return True;
526                       }
527                       close(sock);
528               }
529       }
530
531       return False;
532 }
533
534
535 /********************************************************
536 resolve via "lmhosts" method
537 *********************************************************/
538 static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
539 {
540         /*
541          * "lmhosts" means parse the local lmhosts file.
542          */
543         
544         FILE *fp;
545         pstring lmhost_name;
546         int name_type2;
547
548         DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
549
550         fp = startlmhosts( LMHOSTSFILE );
551         if(fp) {
552                 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
553                         if (strequal(name, lmhost_name) && 
554                             name_type == name_type2) {
555                                 endlmhosts(fp);
556                                 return True; 
557                         }
558                 }
559                 endlmhosts(fp);
560         }
561         return False;
562 }
563
564
565 /********************************************************
566 resolve via "hosts" method
567 *********************************************************/
568 static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
569 {
570         /*
571          * "host" means do a localhost, or dns lookup.
572          */
573         struct hostent *hp;
574
575         DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
576         
577         if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
578                 putip((char *)return_ip,(char *)hp->h_addr);
579                 return True;
580         }
581         return False;
582 }
583
584
585 /********************************************************
586  Resolve a name into an IP address. Use this function if
587  the string is either an IP address, DNS or host name
588  or NetBIOS name. This uses the name switch in the
589  smb.conf to determine the order of name resolution.
590 *********************************************************/
591 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
592 {
593   int i;
594   BOOL pure_address = True;
595   pstring name_resolve_list;
596   fstring tok;
597   char *ptr;
598
599   if (strcmp(name,"0.0.0.0") == 0) {
600     return_ip->s_addr = 0;
601     return True;
602   }
603   if (strcmp(name,"255.255.255.255") == 0) {
604     return_ip->s_addr = 0xFFFFFFFF;
605     return True;
606   }
607    
608   for (i=0; pure_address && name[i]; i++)
609     if (!(isdigit((int)name[i]) || name[i] == '.'))
610       pure_address = False;
611    
612   /* if it's in the form of an IP address then get the lib to interpret it */
613   if (pure_address) {
614     return_ip->s_addr = inet_addr(name);
615     return True;
616   }
617
618   pstrcpy(name_resolve_list, lp_name_resolve_order());
619   ptr = name_resolve_list;
620   if (!ptr || !*ptr) ptr = "host";
621
622   while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
623           if((strequal(tok, "host") || strequal(tok, "hosts"))) {
624                   if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
625                           return True;
626                   }
627           } else if(strequal( tok, "lmhosts")) {
628                   if (resolve_lmhosts(name, return_ip, name_type)) {
629                           return True;
630                   }
631           } else if(strequal( tok, "wins")) {
632                   /* don't resolve 1D via WINS */
633                   if (name_type != 0x1D &&
634                       resolve_wins(name, return_ip, name_type)) {
635                           return True;
636                   }
637           } else if(strequal( tok, "bcast")) {
638                   if (resolve_bcast(name, return_ip, name_type)) {
639                           return True;
640                   }
641           } else {
642                   DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
643           }
644   }
645
646   return False;
647 }
648
649
650
651 /********************************************************
652 find the IP address of the master browser or DMB for a workgroup
653 *********************************************************/
654 BOOL find_master_ip(char *group, struct in_addr *master_ip)
655 {
656         if (resolve_name(group, master_ip, 0x1D)) return True;
657
658         return resolve_name(group, master_ip, 0x1B);
659 }