123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- /*
- Unix SMB/Netbios implementation.
- Version 1.9.
- name query routines
- Copyright (C) Andrew Tridgell 1994-1998
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
- #include "includes.h"
- const char *unix_error_string (int error_num);
- extern pstring scope;
- extern int DEBUGLEVEL;
- /* nmbd.c sets this to True. */
- const BOOL global_in_nmbd = False;
- #if 0
- /****************************************************************************
- interpret a node status response
- ****************************************************************************/
- static void _interpret_node_status(char *p, char *master,char *rname)
- {
- int numnames = CVAL(p,0);
- DEBUG(1,("received %d names\n",numnames));
- if (rname) *rname = 0;
- if (master) *master = 0;
- p += 1;
- while (numnames--)
- {
- char qname[17];
- int type;
- fstring flags;
- int i;
- *flags = 0;
- StrnCpy(qname,p,15);
- type = CVAL(p,15);
- p += 16;
- fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
- if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
- if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
- if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
- if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
- if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
- if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
- if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
- if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
- if (master && !*master && type == 0x1d) {
- StrnCpy(master,qname,15);
- trim_string(master,NULL," ");
- }
- if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
- StrnCpy(rname,qname,15);
- trim_string(rname,NULL," ");
- }
-
- for (i = strlen( qname) ; --i >= 0 ; ) {
- if (!isprint((int)qname[i])) qname[i] = '.';
- }
- DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
- p+=2;
- }
- DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
- IVAL(p,20),IVAL(p,24)));
- }
- #endif /* 0 */
- /****************************************************************************
- do a netbios name query to find someones IP
- returns an array of IP addresses or NULL if none
- *count will be set to the number of addresses returned
- ****************************************************************************/
- struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
- struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
- {
- BOOL found=False;
- int i, retries = 3;
- int retry_time = bcast?250:2000;
- struct timeval tval;
- struct packet_struct p;
- struct packet_struct *p2;
- struct nmb_packet *nmb = &p.packet.nmb;
- static int name_trn_id = 0;
- struct in_addr *ip_list = NULL;
- memset((char *)&p,'\0',sizeof(p));
- (*count) = 0;
- if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
- ((unsigned)getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = bcast;
- nmb->header.nm_flags.recursion_available = False;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
- make_nmb_name(&nmb->question.question_name,name,name_type);
- nmb->question.question_type = 0x20;
- nmb->question.question_class = 0x1;
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
- GetTimeOfDay(&tval);
- if (!send_packet(&p))
- return NULL;
- retries--;
- while (1)
- {
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time)
- {
- if (!retries)
- break;
- if (!found && !send_packet(&p))
- return NULL;
- GetTimeOfDay(&tval);
- retries--;
- }
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- debug_nmb_packet(p2);
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response)
- {
- /*
- * Its not for us - maybe deal with it later
- * (put it on the queue?).
- */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- if (nmb2->header.opcode != 0 ||
- nmb2->header.nm_flags.bcast ||
- nmb2->header.rcode ||
- !nmb2->header.ancount)
- {
- /*
- * XXXX what do we do with this? Could be a redirect, but
- * we'll discard it for the moment.
- */
- free_packet(p2);
- continue;
- }
- ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
- ((*count)+nmb2->answers->rdlength/6));
- if (ip_list)
- {
- DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
- inet_ntoa(p2->ip)));
- for (i=0;i<nmb2->answers->rdlength/6;i++)
- {
- putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
- DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
- (*count)++;
- }
- DEBUG(fn?3:2,(")\n"));
- }
- found=True;
- retries=0;
- free_packet(p2);
- if (fn)
- break;
- /*
- * If we're doing a unicast lookup we only
- * expect one reply. Don't wait the full 2
- * seconds if we got one. JRA.
- */
- if(!bcast && found)
- break;
- }
- }
- return ip_list;
- }
- /********************************************************
- Start parsing the lmhosts file.
- *********************************************************/
- FILE *startlmhosts(const char *fname)
- {
- FILE *fp = sys_fopen(fname,"r");
- if (!fp) {
- DEBUG(4,("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
- fname, unix_error_string (errno)));
- return NULL;
- }
- return fp;
- }
- /********************************************************
- Parse the next line in the lmhosts file.
- *********************************************************/
- BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
- {
- pstring line;
- while(!feof(fp) && !ferror(fp)) {
- pstring ip,flags,extra;
- char *ptr;
- int count = 0;
- *name_type = -1;
- if (!fgets_slash(line,sizeof(pstring),fp))
- continue;
- if (*line == '#')
- continue;
- pstrcpy(ip,"");
- pstrcpy(name,"");
- pstrcpy(flags,"");
- ptr = line;
- if (next_token(&ptr,ip ,NULL,sizeof(ip)))
- ++count;
- if (next_token(&ptr,name ,NULL, sizeof(pstring)))
- ++count;
- if (next_token(&ptr,flags,NULL, sizeof(flags)))
- ++count;
- if (next_token(&ptr,extra,NULL, sizeof(extra)))
- ++count;
- if (count <= 0)
- continue;
- if (count > 0 && count < 2)
- {
- DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
- continue;
- }
- if (count >= 4)
- {
- DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
- continue;
- }
- DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
- if (strchr(flags,'G') || strchr(flags,'S'))
- {
- DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
- continue;
- }
- *ipaddr = *interpret_addr2(ip);
- /* Extra feature. If the name ends in '#XX', where XX is a hex number,
- then only add that name type. */
- if((ptr = strchr(name, '#')) != NULL)
- {
- char *endptr;
- ptr++;
- *name_type = (int)strtol(ptr, &endptr, 16);
- if(!*ptr || (endptr == ptr))
- {
- DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
- continue;
- }
- *(--ptr) = '\0'; /* Truncate at the '#' */
- }
- return True;
- }
- return False;
- }
- /********************************************************
- Finish parsing the lmhosts file.
- *********************************************************/
- void endlmhosts(FILE *fp)
- {
- fclose(fp);
- }
- /********************************************************
- resolve via "bcast" method
- *********************************************************/
- static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
- {
- int sock, i;
-
- /*
- * "bcast" means do a broadcast lookup on all the local interfaces.
- */
- DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
- sock = open_socket_in( SOCK_DGRAM, 0, 3,
- interpret_addr(lp_socket_address()), True );
- if (sock != -1) {
- struct in_addr *iplist = NULL;
- int count;
- int num_interfaces = iface_count();
- static char so_broadcast[] = "SO_BROADCAST";
- set_socket_options(sock, so_broadcast);
- /*
- * Lookup the name on all the interfaces, return on
- * the first successful match.
- */
- for( i = 0; i < num_interfaces; i++) {
- struct in_addr sendto_ip;
- /* Done this way to fix compiler error on IRIX 5.x */
- sendto_ip = *iface_bcast(*iface_n_ip(i));
- iplist = name_query(sock, name, name_type, True,
- True, sendto_ip, &count, NULL);
- if(iplist != NULL) {
- *return_ip = iplist[0];
- free((char *)iplist);
- close(sock);
- return True;
- }
- }
- close(sock);
- }
- return False;
- }
- /********************************************************
- resolve via "wins" method
- *********************************************************/
- static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
- {
- int sock;
- struct in_addr wins_ip;
- BOOL wins_ismyip;
- /*
- * "wins" means do a unicast lookup to the WINS server.
- * Ignore if there is no WINS server specified or if the
- * WINS server is one of our interfaces (if we're being
- * called from within nmbd - we can't do this call as we
- * would then block).
- */
- DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
- if(!*lp_wins_server()) {
- DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
- return False;
- }
- wins_ip = *interpret_addr2(lp_wins_server());
- wins_ismyip = ismyip(wins_ip);
- if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
- sock = open_socket_in( SOCK_DGRAM, 0, 3,
- interpret_addr(lp_socket_address()), True );
-
- if (sock != -1) {
- struct in_addr *iplist = NULL;
- int count;
- iplist = name_query(sock, name, name_type, False,
- True, wins_ip, &count, NULL);
- if(iplist != NULL) {
- *return_ip = iplist[0];
- free((char *)iplist);
- close(sock);
- return True;
- }
- close(sock);
- }
- }
- return False;
- }
- /********************************************************
- resolve via "lmhosts" method
- *********************************************************/
- static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
- {
- /*
- * "lmhosts" means parse the local lmhosts file.
- */
-
- FILE *fp;
- pstring lmhost_name;
- int name_type2;
- DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
- fp = startlmhosts( LMHOSTSFILE );
- if(fp) {
- while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
- if (strequal(name, lmhost_name) &&
- ((name_type2 == -1) || (name_type == name_type2))
- ) {
- endlmhosts(fp);
- return True;
- }
- }
- endlmhosts(fp);
- }
- return False;
- }
- /********************************************************
- resolve via "hosts" method
- *********************************************************/
- static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
- {
- /*
- * "host" means do a localhost, or dns lookup.
- */
- struct hostent *hp;
- DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name));
-
- if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
- putip((char *)return_ip,(char *)hp->h_addr);
- return True;
- }
- return False;
- }
- /********************************************************
- Resolve a name into an IP address. Use this function if
- the string is either an IP address, DNS or host name
- or NetBIOS name. This uses the name switch in the
- smb.conf to determine the order of name resolution.
- *********************************************************/
- BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
- {
- int i;
- BOOL pure_address = True;
- pstring name_resolve_list;
- fstring tok;
- char *ptr;
- if (strcmp(name,"0.0.0.0") == 0) {
- return_ip->s_addr = 0;
- return True;
- }
- if (strcmp(name,"255.255.255.255") == 0) {
- return_ip->s_addr = 0xFFFFFFFF;
- return True;
- }
-
- for (i=0; pure_address && name[i]; i++)
- if (!(isdigit((int)name[i]) || name[i] == '.'))
- pure_address = False;
-
- /* if it's in the form of an IP address then get the lib to interpret it */
- if (pure_address) {
- return_ip->s_addr = inet_addr(name);
- return True;
- }
- pstrcpy(name_resolve_list, lp_name_resolve_order());
- if (name_resolve_list == NULL || *name_resolve_list == '\0')
- pstrcpy(name_resolve_list, "host");
- ptr = name_resolve_list;
- while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
- if((strequal(tok, "host") || strequal(tok, "hosts"))) {
- if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
- return True;
- }
- } else if(strequal( tok, "lmhosts")) {
- if (resolve_lmhosts(name, return_ip, name_type)) {
- return True;
- }
- } else if(strequal( tok, "wins")) {
- /* don't resolve 1D via WINS */
- if (name_type != 0x1D &&
- resolve_wins(name, return_ip, name_type)) {
- return True;
- }
- } else if(strequal( tok, "bcast")) {
- if (resolve_bcast(name, return_ip, name_type)) {
- return True;
- }
- } else {
- DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
- }
- }
- return False;
- }
- #if 0
- /********************************************************
- find the IP address of the master browser or DMB for a workgroup
- *********************************************************/
- BOOL find_master_ip(char *group, struct in_addr *master_ip)
- {
- if (resolve_name(group, master_ip, 0x1D)) return True;
- return resolve_name(group, master_ip, 0x1B);
- }
- #endif /* 0 */
|